home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Creative Computers
/
Creative Computers CD-ROM, Volume 1 (Legendary Design Technologies, Inc.)(1994).iso
/
shareware
/
fractals
/
ifslab
/
src
/
ifslab.c
next >
Wrap
C/C++ Source or Header
|
1994-11-17
|
119KB
|
3,134 lines
/******************************************************************************\
* *
* IFS Lab, Copyright (C) 1992 by N. Zeldes. All rights reserved. *
* *
* Version 1.0, April 9, 1992 *
* *
* An interactive program for exploring the IFS Code method of Fractal Image *
* representation and reconstruction. *
* *
* Requires the Fox/Dawson freeware req.library in libs: directory. *
* *
* Compile under Aztec C 5.0, with -ff option (Fast floating point) *
* and -safmnpsu options (code optimization). *
* Link with +cd option (forces sprite and image data to load in CHIP RAM). *
* Link with IFF files (from CBM IFF Disk, Fish disk #185), and with the glue *
* module for the Fox/Dawson requester library, thus: *
* *
* cc -ff -safmnpsu -i IFF -i req IFSLab.c *
* ln +cd IFSLab.o IFF/putpict.o IFF/ilbmw.o IFF/packer.o *
* IFF/iffw.o IFF/readpict.o IFF/ilbmr.o IFF/unpacker.o IFF/iffr.o *
* IFF/remalloc.o req/myreqglue.o mf.lib c.lib *
* *
\******************************************************************************/
#include <intuition/intuition.h>
#include <exec/memory.h>
/* exec/memory.h required to use AllocMem() */
#include <graphics/text.h>
/* graphics/text.h required for font TextAttr structure */
#include <stdio.h>
#include <math.h> /* Floating point math: sqrt, fabs, trig functions */
#include <errno.h> /* Required by myatan2() */
#include <graphics/display.h> /* needed for definition of INTERLACE */
#include <stdlib.h> /* stdlib.h needed for rand() */
#include <time.h> /* time.h needed for time() */
#include <string.h> /* needed for memset */
#include <ilbm.h> /* Header file from IFF Disk (Note that */
/* ilbm.h #includes compiler.h and iff.h) */
#include <readpict.h> /* From IFF Disk */
#include <remalloc.h> /* From IFF Disk; For ChipAlloc(), RemFree() */
#include <libraries/dos.h> /* For IFF file I/O stuff */
#include <libraries/dosextens.h> /* For the Process structure definition. */
#include <reqbase.h> /* Fox/Dawson file requester header file */
#include "IFSLab.h" /* PowerWindows-generated structures and defines */
#define INTUITION_REV 31L
#define GRAPHICS_REV 31L
#define OUTLINE 0 /* parameters for SetMode() */
#define COLLAGE 1
#define FREEHAND 0 /* drawmode values */
#define LINES 1
#define ERASE 2
#define FILL 3
#define VECTOR 4
#define CODES 0 /* parameters for AboutText() */
#define IFS_THEORY 1
#define HELP1 2
#define HELP2 3
#define AUTHOR 4
#define DEMOTEXT 5
#define WIDTH Window->Width
#define HEIGHT Window->Height
#define GZZWIDTH Window->GZZWidth
#define GZZHEIGHT Window->GZZHeight
#define MAX_N 19 /* max permitted piece index */
struct Screen *Screen = NULL, *ImageScreen;
struct RastPort *scrp; /* Pointer to Screen RastPort */
struct Window *Window = NULL, *NumWindow;
struct RastPort *r; /* Pointer to RastPort of main editing window */
struct Window *ImageWindow; /* Window for rendering Image */
struct RastPort *Textrp; /* Rastport of Text Window */
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
void *MathBase = NULL;
void *MathTransBase = NULL;
struct ReqLib *ReqBase = NULL; /* Fox/Dawson Requester Library */
int drawmode = FREEHAND;
/* Current mode - FREEHAND,LINES,ERASE,FILL (outline) or VECTOR (Collage) */
int exists_outline = 0, exists_image = 0, exists_numwindow = 0;
int renderwidth = 640, renderheight = 400; /* initialize to default */
int renderdepth = 1; /* initialize to default */
long mx, my; /* Current Mouse coordinates in editing */
struct pixel {
long x;
long y;
};
struct piece {
double a, b, c, d, e, f;
double s1, s2, r1, r2;
double dens;
double p;
double det;
UBYTE *piecemap;
struct pixel boxo, boxx, boxy, boxz;
};
struct piece *pieceptr[MAX_N + 1]; /* Array of pointers to piece structures */
int N = -1; /* Index of highest existing Piece Initialized to zero pieces */
int selpiece; /* Index of currently selected Piece */
char curcor; /* Currently dragged Box corner ('o','x','y','z') or none ('0') */
struct pixel ghboxo, ghboxx, ghboxy, ghboxz; /* Current corners of ghost Box */
struct pixel tmpboxo, tmpboxx, tmpboxy, tmpboxz;
struct piece *AllocPiece();
double myatan2(); /* My version of atan2() which is missing in Manx mf.lib */
char *fname, *GetFileName();
struct Library *OpenLibrary();
void *AllocMem(), *AllocRaster();
UBYTE *outlinebufptr=NULL; /* ptr to buffer holding outline in collage mode */
long i; /* handy as a loop index */
/*** IFF error messages (external) */
char MsgOkay[] = { "(IFF_OKAY) A good IFF file" };
char MsgEndMark[] = { "(END_MARK) IFF Loader Error" };
char MsgDone[] = { "(IFF_DONE) Well Done!" };
char MsgDos[] = { "DOS Error - Aborting Load!" };
char MsgNot[] = { "Not an IFF file - Aborting Load!" };
char MsgNoFile[] = { "No such file found - Aborting Load!" };
char MsgClientError[] = { "(CLIENT_ERROR) IFF Checker bug"};
char MsgForm[] = { "(BAD_FORM) IFF Loader Error" };
char MsgShort[] = { "(SHORT_CHUNK) IFF Loader Error" };
char MsgBad[] = { "A mangled IFF file - Aborting Load!" };
/* MUST GET THESE IN RIGHT ORDER!!*/
char *IFFPMessages[-LAST_ERROR+1] = {
/*IFF_OKAY*/ MsgOkay,
/*END_MARK*/ MsgEndMark,
/*IFF_DONE*/ MsgDone,
/*DOS_ERROR*/ MsgDos,
/*NOT_IFF*/ MsgNot,
/*NO_FILE*/ MsgNoFile,
/*CLIENT_ERROR*/ MsgClientError,
/*BAD_FORM*/ MsgForm,
/*SHORT_CHUNK*/ MsgShort,
/*BAD_IFF*/ MsgBad
};
struct FileRequester MyFileReqStruct; /* File Requester stuff */
char filename[FCHARS+1];
char directoryname[DSIZE+1];
char pathname[FCHARS+DSIZE+2+4]; /* +4 to permit space for appending '.ifs' */
/*==========================================================================*/
main()
{
struct Message * GetMsg();
void ReplyMsg();
struct IntuiMessage *message;
ULONG class;
USHORT code, MenuNumber, menuid, itemid, subitemid;
struct MenuItem *ItemAddress(), *ItemAddr;
long labs();
int w; /* temporary int variable */
int hitgadget; /* GadgetID # of last gadget hit by mouse */
struct Gadget *hitgadstruct; /* Gadget Structure of last hit gadget */
int numgadgpending; /* GadgetID of unserviced coeff gadget, or -1 if none */
struct piece tmppiece; /* will be used to hold temporary trans' coeffs */
long mx0,my0, mx1,my1; /* coords of endpoints of ghost line in Lines mode */
int pendown = 0;
/* 0 if mouse SELECT button is currently pressed in window */
SHORT WindowBdrArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* will be filled later to corners of inner GZZ Window */
struct Gadget *gad; /* used as a temporary variable */
/**** Initialize stuff, set up edit window in custom screen etc. ****/
OpenLibraries();
OpenDisplay(); /* Open Outline Sketch window in custom screen */
SetAPen(r, 2L);
WindowBdrArray[2] = WindowBdrArray[4] = GZZWIDTH - 1;
WindowBdrArray[5] = WindowBdrArray[7] = GZZHEIGHT - 1;
/*** Allocate memory for Outline buffer bitmap */
if ((outlinebufptr =
(UBYTE *)AllocMem((long)RASSIZE(WIDTH,HEIGHT), MEMF_CHIP)) == NULL) {
ShowError("Can't allocate Outline Buffer Memory!");
CloseAll();
}
/**** Main Loop ****/
while(1) {
mx = (long)Window->GZZMouseX;
my = (long)Window->GZZMouseY;
if (pendown == 1) {
/*** Do Mouse editing to board per drawmode and mouse coords */
switch (drawmode) {
case FREEHAND:
Draw(r, mx, my);
break;
case LINES:
SetDrMd(r, JAM1|COMPLEMENT); /* COMPLEMENT used for ghost line */
Move(r, mx0, my0);
Draw(r, mx1,my1); /* Undraw previous ghost line */
Move(r, mx0, my0);
Draw(r, mx1 = mx, my1 = my); /* Draw a new ghost line */
SetDrMd(r, JAM1);
break;
case ERASE:
RectFill(r, mx - 2, my - 2, mx + 2, my + 2);
break;
case FILL:
break;
case VECTOR: /* Change the Ghost Vector Box */
if (exists_numwindow || curcor == '0')
break;
/* Check for attempt to size box to a point */
if ( (mx==pieceptr[selpiece]->boxo.x && my==pieceptr[selpiece]->boxo.y)
&& ( (curcor == 'z') ||
(curcor == 'x' &&
pieceptr[selpiece]->boxy.x == pieceptr[selpiece]->boxo.x &&
pieceptr[selpiece]->boxy.y == pieceptr[selpiece]->boxo.y) ||
(curcor == 'y' &&
pieceptr[selpiece]->boxx.x == pieceptr[selpiece]->boxo.x &&
pieceptr[selpiece]->boxx.y == pieceptr[selpiece]->boxo.y)
)
)
mx = (mx == 0) ? 1 : mx - 1; /* If attempted, tweak mx to avoid */
ComputeNewBox(); /* Compute New Ghost Box from mouse coords */
ToggleGhostBox(); /* Undraw old ghost box */
ghboxo = tmpboxo; /* Update ghost box variables */
ghboxx = tmpboxx;
ghboxy = tmpboxy;
ghboxz = tmpboxz;
ToggleGhostBox(); /* Draw new ghost box */
break;
} /* End Switch */
} /* end if pendown == 1 */
/* Get an IDCMP event, if any, from Window */
if (message = (struct IntuiMessage *)GetMsg(Window->UserPort)) {
class = message->Class;
code = message->Code;
ReplyMsg(message);
}
else /* no message */
class = code = NULL; /* so event routines below will be skipped */
/*** Go case by case over possible events from port */
if (class == MOUSEBUTTONS) { /*** Respond to user mousebutton clicks */
if (code == SELECTDOWN) {
pendown = 1;
if (drawmode != ERASE)
exists_outline = 1;
switch (drawmode) {
case FREEHAND:
case ERASE:
Move(r, mx, my);
break;
case LINES:
mx0 = mx1 = mx; /* Attach both ends of line to pixel */
my0 = my1 = my;
break;
case FILL:
ModifyMousePtr(Window, 1); /* Bring up 'ZZ' pointer */
SetAPen(r, 2L);
Move(r, 0L, 0L);
PolyDraw(r,5L,WindowBdrArray); /* temporary border to prevent */
Flood(r, 0L, mx, my); /* messes on flood fill to edge */
SetAPen(r, 0L);
Move(r, 0L, 0L);
PolyDraw(r,5L,WindowBdrArray);
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
break;
case VECTOR:
if (exists_numwindow)
break;
/*** Decide which corner, if any, the user clicked on */
curcor = '0';
w = selpiece; /* Just to keep source lines shorter... */
if (labs(mx-pieceptr[w]->boxo.x)<5&&labs(my-pieceptr[w]->boxo.y)<5)
curcor = 'o';
if (labs(mx-pieceptr[w]->boxx.x)<5&&labs(my-pieceptr[w]->boxx.y)<5)
curcor = 'x';
if (labs(mx-pieceptr[w]->boxy.x)<5&&labs(my-pieceptr[w]->boxy.y)<5)
curcor = 'y';
if (labs(mx-pieceptr[w]->boxz.x)<5&&labs(my-pieceptr[w]->boxz.y)<5)
curcor = 'z';
if (curcor != '0') { /* Set up ghost box for starters */
/*** Update ghost box variables by calling ComputeNewBox() */
ComputeNewBox();
ghboxo = tmpboxo; /* Structure Assignments */
ghboxx = tmpboxx;
ghboxy = tmpboxy;
ghboxz = tmpboxz;
ToggleGhostBox(); /* Draw initial ghost box */
}
break;
} /* End switch */
} /* End if SELECTDOWN */
else if (code == SELECTUP) {
pendown = 0;
switch (drawmode) {
case FREEHAND:
case ERASE:
case FILL:
break;
case LINES:
SetAPen(r, 2L); /* Draw final line (Jam onto last Ghost line) */
Move(r,mx0, my0);
Draw(r, mx1, my1);
break;
case VECTOR:
if (exists_numwindow || curcor == '0')
break;
ToggleGhostBox(); /* Undraw Ghost Box */
/*** Compute all coeffs from ghbox corners, put into tmppiece */
tmppiece = *pieceptr[selpiece]; /* Structure assignment */
tmppiece.s1 =
sqrt((double)((ghboxx.x-ghboxo.x)*(ghboxx.x-ghboxo.x) +
(ghboxx.y-ghboxo.y)*(ghboxx.y-ghboxo.y)))/GZZWIDTH;
tmppiece.s2 =
sqrt((double)((ghboxy.x-ghboxo.x)*(ghboxy.x-ghboxo.x) +
(ghboxy.y-ghboxo.y)*(ghboxy.y-ghboxo.y)))/GZZHEIGHT;
tmppiece.r1 = myatan2((double)(ghboxx.y-ghboxo.y),
(double)(ghboxx.x-ghboxo.x));
tmppiece.r2 = myatan2((double)(ghboxo.x-ghboxy.x),
(double)(ghboxy.y-ghboxo.y));
tmppiece.a = tmppiece.s1*cos(tmppiece.r1);
tmppiece.b = -tmppiece.s2*sin(tmppiece.r2);
tmppiece.c = tmppiece.s1*sin(tmppiece.r1);
tmppiece.d = tmppiece.s2*cos(tmppiece.r2);
tmppiece.e = (double)(ghboxo.x)/GZZWIDTH;
tmppiece.f = (double)(ghboxo.y)/GZZWIDTH;
/*** Erase Plane 3 before transformation delay */
SetWrMsk(r,0xFFF8); /* Write-protect planes 0,1,2 */
SetRast(r, 0L);
SetWrMsk(r,0xFFFF);
/* Transform the selected piece per user drag of vector box */
TransformPiece(outlinebufptr,
pieceptr[selpiece]->piecemap, &tmppiece);
/*** Erase Plane 2, then Blit Selected Piece from piecemap to it */
SetWrMsk(r,0xFFF4); /* Write-protect planes 0,1,3 */
SetRast(r, 0L);
SetAPen(r, 4L);
BltTemplate((char*)pieceptr[selpiece]->piecemap,
(long)Window->BorderLeft,(long)WIDTH/8, r, 0L, 0L,
(long)GZZWIDTH, (long)GZZHEIGHT);
/* Rastport WrMask will be restored in DrawBox() called below */
/*** Recompute probabilities and update piece structures */
tmppiece.boxo = ghboxo; /* structure assignment */
tmppiece.boxx = ghboxx; /* structure assignment */
tmppiece.boxy = ghboxy; /* structure assignment */
tmppiece.boxz = ghboxz; /* structure assignment */
*pieceptr[selpiece] = tmppiece; /* structure assignment */
pieceptr[selpiece]->det =
fabs(tmppiece.a * tmppiece.d - tmppiece.b * tmppiece.c);
if (pieceptr[selpiece]->det == 0.0)
pieceptr[selpiece]->det = 0.01;
ComputeProbs(); /* Adjust all piece probabilities */
DrawBox(); /* Redraw Vector Box for modified selected piece */
curcor = '0';
break;
} /* End switch */
} /* End else if SELECTUP */
} /* End if MOUSEBUTTONS */
else if (class == GADGETUP) { /*** Respond to Gadget clicked in Window */
hitgadget = ((struct Gadget *)(message->IAddress))->GadgetID;
/* ID# of just-selected gadget structure */
if (hitgadget <= 3) /* a draw mode gadget in Outline mode */
HiliteGadget(hitgadget);
switch(hitgadget) {
case 0:
drawmode = FREEHAND;
SetAPen(r,2L);
break;
case 1:
drawmode = LINES;
SetAPen(r,2L);
break;
case 2:
drawmode = ERASE;
SetAPen(r, 0L);
SetOPen(r, 0L);
break;
case 3:
drawmode = FILL;
SetOPen(r, 2L); /* (A Pen defined before doing the flood fill) */
break;
case 4: /* CLROUT (Clear Outline) gadget */
SetRast(r, 0L);
exists_outline = 0;
if(drawmode == ERASE || drawmode == FILL) {
drawmode = FREEHAND;
SetAPen(r,2L);
HiliteGadget(0);
}
break;
case 5: /* DONE gadget */
SetMode(COLLAGE);
AddDefPiece();
DrawCollage();
break;
case 6: /* ADD gadget */
AddDefPiece();
DrawCollage();
if (exists_numwindow)
UpdateNumStrings();
break;
case 7: /* DUP gadget */
DupSelPiece();
DrawCollage();
if (exists_numwindow)
UpdateNumStrings();
break;
case 8: /* SELECT gadget */
if (--selpiece < 0)
selpiece = N;
DrawCollage();
if (exists_numwindow)
UpdateNumStrings();
break;
case 9: /* DELETE gadget */
DeleteSelPiece();
DrawCollage();
ComputeProbs();
if (exists_numwindow)
UpdateNumStrings();
break;
case 10: /* CLRIFS gadget */
ClearIFS();
AddDefPiece();
DrawCollage();
if (exists_numwindow)
UpdateNumStrings();
break;
case 11: /* NUMBERS Gadget */
if (!exists_numwindow) {
UpdateNumStrings();
OpenNumWindow();
numgadgpending = -1;
}
break;
} /* end switch hitgadget */
} /* End else if GADGETUP */
else if (class == MENUPICK) { /*** Respond to menu selections */
MenuNumber = code; /* (First) item selection returned by IDCMP */
while (MenuNumber != MENUNULL) { /*** service multiply chosen items */
/* (if any) */
ItemAddr = ItemAddress(&MenuList1, (long)MenuNumber);
menuid = MENUNUM(MenuNumber); /* Extract menu, item from IDCMP code */
itemid = ITEMNUM(MenuNumber);
subitemid = SUBNUM(MenuNumber);
if (menuid == 0) { /* PROJECT Menu */
switch (itemid) {
case 0: /* NEW */
if (SetMode(OUTLINE) == 1) {
SetRast(r, 0L);
exists_outline = 0;
if (exists_image)
CloseImageScreen();
}
break;
case 1: /* EDIT OUTLINE */
SetMode(OUTLINE);
break;
case 2: /* LOAD FILE (with subitems) */
if(ReqBase == NULL) { /* req.library missing - no file I/O */
ShowError("req.library not found!");
break;
}
fname = GetFileName("File to Load:");
if (*fname != '\0') {
switch (subitemid) {
case 0: /* Load Outline */
if (SetMode(OUTLINE) == 1)
LoadILBM(fname, 0);
break;
case 1: /* Load IFS */
SetMode(COLLAGE);
if (LoadIFS(fname) == NULL) { /* If load failed */
ClearIFS();
AddDefPiece();
DrawCollage();
}
break;
case 2: /* Load Image */
LoadILBM(fname, 1);
break;
} /* end switch subitemid */
} /* end if *fname etc */
break;
case 3: /* SAVE FILE (with subitems) */
if(ReqBase == NULL) { /* req.library missing - no file I/O */
ShowError("req.library not found!");
break;
}
switch (subitemid) {
case 0: /* Save IFS */
SaveIFS();
break;
case 1: /* Save Image */
SaveILBM();
break;
} /* end switch subitemid */
break;
case 4: /* OPTIMIZE */
if (drawmode != VECTOR)
ShowError("No IFS to Optimize!");
else
Optimize(1);
break;
case 5: /* QUIT */
CloseAll();
break;
} /* end switch itemid */
} /* end if menuid == 0) */
else if (menuid == 1) { /* DISPLAY Menu */
switch (itemid) {
case 0: /* SHOW CODES */
if (drawmode != VECTOR)
ShowError("No IFS!");
else
AboutText(CODES);
break;
case 1: /* SHOW IMAGE */
if (exists_image) {
MoveScreen(ImageScreen, 0L, (long)(-1*ImageScreen->TopEdge));
ScreenToFront(ImageScreen);
}
else
ShowError("No Image!");
break;
} /* end switch itemid */
} /* end else if menuid == 1) */
else if (menuid == 2) { /* RENDER Menu */
switch (itemid) {
case 0: /* RESOLUTION (with subitems) */
renderwidth = (subitemid > 0) ? 640 : 320;
renderheight = (subitemid > 1) ? 400 : 200;
break;
case 1: /* GRAY LEVELS (with subitems) */
renderdepth = subitemid + 1;
break;
case 2: /* START */
while(message = (struct IntuiMessage *)GetMsg(Window->UserPort))
ReplyMsg(message); /* Clean out IDCMP port before closing it */
ModifyIDCMP(Window, NULL); /* Disable IDCMP during rendering */
ClearMenuStrip(Window); /* remove main window menus during render*/
RenderImage(0); /* render the attractor in Image Screen */
SetMenuStrip(Window, &MenuList1);
ModifyIDCMP(Window, MOUSEBUTTONS|GADGETUP|MENUPICK);
break;
} /* end switch itemid */
} /* end else if menuid == 2) */
else if (menuid == 3) { /* ABOUT Menu */
switch (itemid) {
case 0: /* IFS THEORY */
AboutText(IFS_THEORY);
break;
case 1: /* HELP */
AboutText(HELP1);
AboutText(HELP2);
break;
case 2: /* AUTHOR */
AboutText(AUTHOR);
break;
case 3: /* DEMO */
DoDemo();
break;
} /* end switch itemid */
} /* end else if menuid == 3) */
MenuNumber = ItemAddr->NextSelect;
/* Loop back for next multiply selected item, if any */
} /* end while MenuNumber != MENUNULL */
} /* end else if MENUPICK */
/*** Get & serve an IDCMP event, if any, from Coefficients Window */
if (exists_numwindow) {
if (message = (struct IntuiMessage *)GetMsg(NumWindow->UserPort)) {
ReplyMsg(message);
/* Note that all events in this window are GADGETUP, GADGETDOWN */
/* or CLOSEWINDOW */
if (message->Class == CLOSEWINDOW) {
CloseWindow(NumWindow);
exists_numwindow = 0;
numgadgpending = -1;
SetMenuStrip(Window, &MenuList1);
}
else if (message->Class == GADGETDOWN) { /* ENTER or string gadget */
if (numgadgpending != -1)
RecomputeCoeffs(numgadgpending);
hitgadstruct = (struct Gadget *)(message->IAddress);
/* pointer to just-hit gadget */
numgadgpending = hitgadstruct->GadgetID;
/* ID# of just-selected gadget structure */
/**** Refresh all string gadgets except just-hit one */
for(gad = &NumAcoeffGadg; gad != NULL; gad = gad->NextGadget)
if (gad->GadgetID != numgadgpending)
RefreshGList(gad, NumWindow, NULL, 1L);
if (numgadgpending == 12)
numgadgpending = -1; /* It was only the ENTER Gadget */
}
else if (message->Class == GADGETUP) {
hitgadget = ((struct Gadget *)(message->IAddress))->GadgetID;
/* ID# of just-selected gadget structure */
switch (hitgadget) {
case 12: /* ENTER */
tmppiece = *pieceptr[selpiece]; /* Structure assignment */
/* Copy all coeffs from string gadgets to tmppiece */
sscanf((char*)NumNumR2coeffGadgSIBuff, "%lf", &tmppiece.r2);
sscanf((char*)NumNumR1coeffGadgSIBuff, "%lf", &tmppiece.r1);
sscanf((char*)NumNumS2coeffGadgSIBuff, "%lf", &tmppiece.s2);
sscanf((char*)NumNumS1coeffGadgSIBuff, "%lf", &tmppiece.s1);
sscanf((char*)NumNumPcoeffGadgSIBuff, "%lf", &tmppiece.p);
sscanf((char*)NumNumDenscoeffGadgSIBuff, "%lf",
&tmppiece.dens);
sscanf((char*)NumNumFcoeffGadgSIBuff, "%lf", &tmppiece.f);
sscanf((char*)NumNumEcoeffGadgSIBuff, "%lf", &tmppiece.e);
sscanf((char*)NumNumDcoeffGadgSIBuff, "%lf", &tmppiece.d);
sscanf((char*)NumNumCcoeffGadgSIBuff, "%lf", &tmppiece.c);
sscanf((char*)NumNumBcoeffGadgSIBuff, "%lf", &tmppiece.b);
sscanf((char*)NumNumAcoeffGadgSIBuff, "%lf", &tmppiece.a);
tmppiece.r1 = tmppiece.r1*0.017453293; /* convert degs to radians*/
tmppiece.r2 = tmppiece.r2*0.017453293;
/*** Erase Plane 3 before transformation delay */
SetWrMsk(r,0xFFF8); /* Write-protect planes 0,1,2 */
SetRast(r, 0L);
SetWrMsk(r, 0xFFFF);
/* Transform the selected piece per user-entered coefficients */
TransformPiece(outlinebufptr,
pieceptr[selpiece]->piecemap, &tmppiece);
/*** Erase Plane 2, then Blit Selected Piece from piecemap to it */
SetWrMsk(r,0xFFF4); /* Write-protect planes 0,1,3 */
SetRast(r, 0L);
SetAPen(r, 4L);
BltTemplate((char*)pieceptr[selpiece]->piecemap,
(long)Window->BorderLeft,(long)WIDTH/8, r, 0L, 0L,
(long)GZZWIDTH, (long)GZZHEIGHT);
/* Rastport WrMask will be restored in DrawBox() called below */
/*** Compute new Box corners from new coeffs */
tmppiece.boxo.x = tmppiece.e * GZZWIDTH;
tmppiece.boxo.y = tmppiece.f * GZZWIDTH; /* sic! */
tmppiece.boxx.x = (tmppiece.a + tmppiece.e) * GZZWIDTH;
tmppiece.boxx.y = (tmppiece.c + tmppiece.f) * GZZWIDTH;
tmppiece.boxy.x = (tmppiece.b*GZZHEIGHT/GZZWIDTH + tmppiece.e) *
GZZWIDTH;
tmppiece.boxy.y = (tmppiece.d*GZZHEIGHT/GZZWIDTH + tmppiece.f) *
GZZWIDTH;
tmppiece.boxz.x =
tmppiece.boxy.x + tmppiece.boxx.x - tmppiece.boxo.x;
tmppiece.boxz.y =
tmppiece.boxy.y + tmppiece.boxx.y - tmppiece.boxo.y;
*pieceptr[selpiece] = tmppiece; /* structure assignment */
/*** Recompute probabilities and update piece structures */
pieceptr[selpiece]->det =
fabs(tmppiece.a * tmppiece.d - tmppiece.b * tmppiece.c);
if (pieceptr[selpiece]->det == 0.0)
pieceptr[selpiece]->det = 0.01;
ComputeProbs(); /* Adjust all piece probabilities */
DrawBox(); /* Redraw Vector Box for modified selected piece */
break;
default: /* GADGETUP on any coefficient string gadget */
numgadgpending = -1;
RecomputeCoeffs(hitgadget);
RefreshGadgets(&NumGadgetList3, NumWindow, NULL);
break;
} /* end switch hitgadget */
} /* end else if ... GADGETUP */
} /* end if message etc of coeffs window */
} /* end if exists_numwindow */
/*** Get & serve an IDCMP event, if any, from Image Window */
/* Note that all events in this window are MOUSEBUTTONS */
if (exists_image) {
if (message = (struct IntuiMessage *)GetMsg(ImageWindow->UserPort)) {
ReplyMsg(message);
if (message->Code == SELECTUP) { /* User clicked - push Image to back*/
ScreenToBack(ImageScreen);
MoveScreen(ImageScreen, 0L, (long)(-1*ImageScreen->TopEdge));
ScreenToFront(Screen);
ActivateWindow(Window);
}
}
} /* End if exists_image */
} /* End while of main loop */
} /* End main() */
/*=========================================================================*/
char * GetFileName(prompt) /* Returns pointer to a filename selected from */
char *prompt; /* a file requester. Prompt appears at top of requester */
/* window. If user selected CANCEL,returns a nullstring */
/* Places the requester in a custom 640x200 screen. */
/* Uses the Fox/Dawson File Requester; you must link */
/* with glue module myreqglue.o. You need to include */
/* reqbase.h and also libraries/dosextens.h (for the */
/* Process structure). */
{
struct Screen *ReqScreen;
struct Window *ReqWindow;
struct NewScreen ns;
struct Screen *OpenScreen();
struct NewWindow nw;
struct Window *OpenWindow();
struct Task *FindTask();
struct Process *myprocess;
APTR oldwindowptr;
/* Link the buffers to the FileRequester struct (all declared as globals) */
MyFileReqStruct.File = filename;
MyFileReqStruct.Dir = directoryname;
MyFileReqStruct.PathName = pathname;
/*** Open a window in a custom Hires screen for requester display */
ns.LeftEdge = 0; /*** Initialize a NewScreen structure */
ns.TopEdge = 0;
ns.Width = 640;
ns.Height = 200;
ns.Depth = 2;
ns.DetailPen = 0; /* Colour of text in screen title bar */
ns.BlockPen = 1; /* Colour of screen Title Bar */
ns.ViewModes = HIRES;
ns.Type = CUSTOMSCREEN;
ns.Font = &TOPAZ80;
ns.DefaultTitle = NULL;
ns.Gadgets = NULL;
ns.CustomBitMap = NULL;
nw.LeftEdge = 0; /*** Initialize a NewWindow structure */
nw.TopEdge = 0;
nw.Width = 640;
nw.Height = 200;
nw.DetailPen = 0; /* Menu title text color */
nw.BlockPen = 1; /* Menu item box and title bar background */
nw.IDCMPFlags = NULL;
nw.Flags = ACTIVATE|NOCAREREFRESH;
nw.FirstGadget = NULL;
nw.CheckMark = NULL;
nw.Title = (UBYTE*)" ";
nw.Screen = NULL; /* Will set it to ReqScreen after the screen is opened */
nw.BitMap = NULL;
nw.MinWidth = 0;
nw.MinHeight = 0;
nw.MaxWidth = 0;
nw.MaxHeight = 0;
nw.Type = CUSTOMSCREEN;
/*** Open a Hires screen to place the requester in */
if ((ReqScreen = (struct Screen *) OpenScreen(&ns)) == NULL) {
ShowError("Couldn't open Requester screen!!!");
pathname[0] = '\0'; /* make returned buffer a nullstring */
return(pathname);
}
/*** Open the Window to place the requester in */
nw.Screen = ReqScreen;
if ((ReqWindow = (struct Window *) OpenWindow(&nw)) == NULL) {
CloseScreen(ReqScreen);
ShowError("Couldn't open Requester window!!!");
pathname[0] = '\0'; /* make returned buffer a nullstring */
return(pathname);
}
/* Set pointer to tell req.library requesters where to appear */
myprocess = (struct Process *)FindTask((char *)0);
oldwindowptr = myprocess->pr_WindowPtr;
myprocess->pr_WindowPtr = (APTR)ReqWindow;
/*** Set up file requester structure fields to customize requester */
MyFileReqStruct.Title = prompt; /* Text at top of requester */
MyFileReqStruct.dirnamescolor = 3; /* colours of requester elements */
MyFileReqStruct.devicenamescolor = 3;
MyFileReqStruct.WindowLeftEdge = 0;
MyFileReqStruct.WindowTopEdge = 0;
MyFileReqStruct.Flags = FRQCACHINGM | /* Directory Caching */
FRQABSOLUTEXYM | /* Fix requester position in screen */
FRQNOHALFCACHEM| /* Don't cache half-read directories */
FRQNODRAGM; /* No drag bar on requester */
if (FileRequester(&MyFileReqStruct) == NULL) /* Call the File Requester */
pathname[0] = '\0'; /* If user selected no file, return a nullstring*/
/* restore pr_WindowPtr before closing the window! */
myprocess->pr_WindowPtr = oldwindowptr;
CloseWindow(ReqWindow); /*** Close requester screen stuff and return */
CloseScreen(ReqScreen);
return(pathname); /* Will be the pointer to a string which now contains the */
/* full file name selected, or a NULL string if the user */
/* selected CANCEL or no filename */
}
/*===========================================================================*/
OpenLibraries() /* Open needed libraries */
{
IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library",INTUITION_REV);
if (IntuitionBase == NULL) {
printf("Can't open Intuition library!!!!!!\n");
CloseAll();
}
GfxBase = (struct GfxBase *)
OpenLibrary("graphics.library",GRAPHICS_REV);
if (GfxBase == NULL) {
printf("Can't open graphics library!!!!!!\n");
CloseAll();
}
MathBase = (void *)OpenLibrary("mathffp.library",0L);
if (MathBase == NULL) {
printf("Can't open mathffp library!!!!!!\n");
CloseAll();
}
MathTransBase = (void *)OpenLibrary("mathtrans.library",0L);
if (MathTransBase == NULL) {
printf("Can't open mathtrans library!!!!!!\n");
CloseAll();
}
ReqBase = (struct ReqLib *)OpenLibrary("req.library", 0L);
if (ReqBase == NULL) {
printf("Couldn't open req.library!!!!!!\n");
printf("IFSlab requires req.library in libs: to be able to do file I/O\n");
}
}
/*=========================================================================*/
OpenDisplay() /* Open Outline Sketch window in custom screen */
{
/* NEWSCREENSTRUCTURE, PALETTE and NewWindowStructure1 are in IFSLab.h */
/* and, along with pointers Window, Screen, have been declared externally */
struct Screen *OpenScreen();
struct Window *OpenWindow();
struct ViewPort *vp;
/*** Open the screen */
if ((Screen = (struct Screen *) OpenScreen(&NEWSCREENSTRUCTURE)) == NULL) {
printf("\nCouldn't open screen!!!!\n");
CloseAll();
}
/*** Link Custom colours defined in PALETTE to screen's ViewPort */
vp = &(Screen->ViewPort);/* ptr to viewport structure assoc'd with screen */
LoadRGB4(vp,PALETTE,16L); /* Change to custom colors defined above */
/*** Open the Window */
NewWindowStructure1.Screen = Screen;
if ((Window = (struct Window *) OpenWindow(&NewWindowStructure1)) == NULL) {
printf("\nCouldn't open window!!!!\n");
CloseAll();
}
scrp = &(Screen->RastPort); /* Screen RastPort,used to draw in outer window*/
SetDrMd(scrp, JAM1);
SetAPen(scrp, 1L);
r = (Window->RPort); /* Window's rastport, used for drawing in GZZ bitmap */
SetDrMd(r, JAM1);
HiliteGadget(0);
SetMenuStrip(Window,&MenuList1);
OffMenu(Window, NOITEM<<5 | 2); /* disable render menu and its items */
}
/*===========================================================================*/
OpenNumWindow() /* Open Coefficients Window and disable menus */
{
/* Assumes window is not open already */
NumNewWindowStructure3.Screen = Screen;
if ((NumWindow = (struct Window *)OpenWindow(&NumNewWindowStructure3))
== NULL) {
ShowError("Error - Couldn't open coeffs window");
return;
}
ClearMenuStrip(Window); /* remove main window menus while Coeffs window on */
SetWindowTitles(NumWindow, -1L, (char *)" Collage Editor");
exists_numwindow = 1;
}
/*===========================================================================*/
CloseAll() /* Close everything neatly and exit program */
{
if (exists_image)
CloseImageScreen();
for (i = 0; i <= N; i++) /* Dealocate Pieces' struct and piecemap memory */
FreePiece(pieceptr[i]);
if (outlinebufptr)
FreeMem(outlinebufptr, (long)RASSIZE(WIDTH, HEIGHT));
if (Window) {
ClearMenuStrip(Window);
CloseWindow(Window);
}
if (exists_numwindow)
CloseWindow(NumWindow);
if (Screen)
CloseScreen(Screen);
if (IntuitionBase)
CloseLibrary(IntuitionBase);
if (GfxBase)
CloseLibrary(GfxBase);
if (MathBase)
CloseLibrary(MathBase);
if (MathTransBase)
CloseLibrary(MathTransBase);
if (ReqBase) {
PurgeFiles(&MyFileReqStruct); /* function in req.library */
CloseLibrary(ReqBase);
}
exit(0);
}
/*===========================================================================*/
int SetMode(newmode) /* Sets up and enters requested mode */
int newmode; /* newmode can be OUTLINE or COLLAGE */
{ /* returns 1 normally; returns 0 if user chose CANCEL in */
/* "IFS will be LOST" requester */
BOOL AutoRequest();
static struct IntuiText Cancel = {
3,0, /* FrontPen, BackPen */
JAM1, /* DrawMode */
6,3, /* LeftEdge, TopEdge */
&TOPAZ80, /* ITextFont */
(UBYTE*)"Cancel", /* IText */
NULL /* NextText */
};
static struct IntuiText Doit, ReqBodyText;
Doit = ReqBodyText = Cancel; /* structure assignment */
ReqBodyText.IText = (UBYTE *)" IFS will be LOST!";
ReqBodyText.TopEdge = 8;
Doit.IText = (UBYTE *)"Do it!";
switch (newmode) {
case OUTLINE:
if (drawmode != VECTOR) /* already in desired mode! */
return(1);
if (AutoRequest(Window, &ReqBodyText, &Doit, &Cancel,
NULL, NULL, 180L, 56L) == FALSE) {
/* Set IDCMP flags right in case AutoRequest() messed 'em up */
ModifyIDCMP(Window, MOUSEBUTTONS|GADGETUP|MENUPICK);
return(0);
}
ModifyIDCMP(Window, MOUSEBUTTONS|GADGETUP|MENUPICK); /* After AutoReq. */
ClearIFS();
RemoveGList(Window, &CollageGadgetList2, 6L);
AddGList(Window, &GadgetList1, 0L, 6L, NULL); /* change gadgets */
SetDrMd(scrp, JAM1);
SetAPen(scrp, 0L);
RectFill(scrp, 280L, 12L, 316L, 117L); /* Blot out old gadget images */
RefreshGadgets(&GadgetList1, Window, NULL);
OffMenu(Window, NOITEM<<5 | 2); /* disable render menu and its items */
SetWindowTitles(Window, -1L, " Outline Editor");
drawmode = FREEHAND;
HiliteGadget(0);
SetAPen(r, 2L);
break;
case COLLAGE:
if (drawmode == VECTOR) /* already in desired mode! */
return(1);
if (exists_outline == 0)
PutDefOutline();
CopyMem((char*)Window->RPort->BitMap->Planes[1],
(char*)outlinebufptr, (long)RASSIZE(WIDTH,HEIGHT));
RemoveGList(Window, &GadgetList1, 6L);
AddGList(Window, &CollageGadgetList2, 0L, 6L, NULL);
SetDrMd(scrp, JAM1);
SetAPen(scrp, 0L);
RectFill(scrp, 280L, 12L, 316L, 117L); /* Blot out old gadget images */
RefreshGadgets(&CollageGadgetList2, Window, NULL);
OnMenu(Window, NOITEM<<5 | 2); /* Enable render menu and its items */
SetWindowTitles(Window, -1L, " Collage Editor");
drawmode = VECTOR;
curcor = '0';
break;
} /* end switch newmode */
return(1);
}
/*===========================================================================*/
DupSelPiece() /* Generate a copy of Selected Piece, make it highest */
{ /* numbered and Selected. Increment N. */
if (N >= MAX_N) {
ShowError("Too many transformations");
return;
}
/*** Allocate and fill piece structure, make it Selected */
if ((pieceptr[++N] = AllocPiece()) == NULL) { /* Allocate Piece */
N--; /* if couldn't allocate piece */
if (N == -1) { /* No memory for even one Piece - Quit program */
ShowError("Re-run with more free memory!");
CloseAll();
}
return;
}
pieceptr[N]->a = pieceptr[selpiece]->a;
pieceptr[N]->b = pieceptr[selpiece]->b;
pieceptr[N]->c = pieceptr[selpiece]->c;
pieceptr[N]->d = pieceptr[selpiece]->d;
pieceptr[N]->e = pieceptr[selpiece]->e;
pieceptr[N]->f = pieceptr[selpiece]->f;
pieceptr[N]->s1 = pieceptr[selpiece]->s1;
pieceptr[N]->s2 = pieceptr[selpiece]->s2;
pieceptr[N]->r1 = pieceptr[selpiece]->r1;
pieceptr[N]->r2 = pieceptr[selpiece]->r2;
pieceptr[N]->dens = 1.0;
pieceptr[N]->det = pieceptr[selpiece]->det;
pieceptr[N]->boxo = pieceptr[selpiece]->boxo; /* Structure assignment! */
pieceptr[N]->boxx = pieceptr[selpiece]->boxx; /* Structure assignment! */
pieceptr[N]->boxy = pieceptr[selpiece]->boxy; /* Structure assignment! */
pieceptr[N]->boxz = pieceptr[selpiece]->boxz; /* Structure assignment! */
ComputeProbs(); /* Adjust all Piece probabilities */
/* Copy selected piece's piecemap to the new piece's piecemap */
CopyMem((char*)pieceptr[selpiece]->piecemap, (char*)pieceptr[N]->piecemap,
(long)RASSIZE(WIDTH,GZZHEIGHT));
selpiece = N; /* make this Piece Selected */
}
/*===========================================================================*/
AddDefPiece() /* Generate a default Piece of current Outline, make */
{ /* it highest numbered and Selected. Increment N. */
if (N >= MAX_N) {
ShowError("Too many transformations");
return;
}
/*** Allocate and fill piece structure, make it Selected */
if ((pieceptr[++N] = AllocPiece()) == NULL) { /* Allocate Piece */
N--; /* if couldn't allocate piece */
if (N == -1) { /* No memory for even one Piece - Quit program */
ShowError("Re-run with more free memory!");
CloseAll();
}
return;
}
pieceptr[N]->a = 0.5;
pieceptr[N]->b = 0.0;
pieceptr[N]->c = 0.0;
pieceptr[N]->d = 0.5;
pieceptr[N]->e = 0.25;
pieceptr[N]->f = 0.16938406; /* = 0.25*GZZHEIGHT/GZZWIDTH */
pieceptr[N]->s1 = 0.5;
pieceptr[N]->s2 = 0.5;
pieceptr[N]->r1 = 0.0;
pieceptr[N]->r2 = 0.0;
pieceptr[N]->dens = 1.0;
pieceptr[N]->det = 0.25;
pieceptr[N]->boxo.x = 0.25 * GZZWIDTH;
pieceptr[N]->boxo.y = 0.25 * GZZHEIGHT;
pieceptr[N]->boxx.x = 0.75 * GZZWIDTH;
pieceptr[N]->boxx.y = 0.25 * GZZHEIGHT;
pieceptr[N]->boxy.x = 0.25 * GZZWIDTH;
pieceptr[N]->boxy.y = 0.75 * GZZHEIGHT;
pieceptr[N]->boxz.x = 0.75 * GZZWIDTH;
pieceptr[N]->boxz.y = 0.75 * GZZHEIGHT;
ComputeProbs(); /* Adjust all Piece probabilities */
/* Transform Outline by this piece's transformation into its piecemap */
TransformPiece(outlinebufptr, pieceptr[N]->piecemap, pieceptr[N]);
selpiece = N; /* make this Piece Selected */
}
/*===========================================================================*/
ComputeProbs() /* Recompute all piece probabilities */
{
double sum = 0;
for (i = 0; i <= N; i++)
sum = sum + pieceptr[i]->dens * pieceptr[i]->det;
for (i = 0; i <= N; i++)
pieceptr[i]->p = (pieceptr[i]->dens * pieceptr[i]->det)/sum;
}
/*===========================================================================*/
DrawBox() /* Erase bitplane 3, and draw Vector Box of Selected Piece in it */
{
SetWrMsk(r,0xFFF8); /* Write-protect planes 0,1,2 */
SetRast(r, 0L); /* Erase plane 3 */
SetAPen(r, 8L); /*** Draw Vector Box */
Move(r, pieceptr[selpiece]->boxo.x, pieceptr[selpiece]->boxo.y);
Draw(r, pieceptr[selpiece]->boxx.x, pieceptr[selpiece]->boxx.y);
Draw(r, pieceptr[selpiece]->boxz.x, pieceptr[selpiece]->boxz.y);
Draw(r, pieceptr[selpiece]->boxy.x, pieceptr[selpiece]->boxy.y);
Draw(r, pieceptr[selpiece]->boxo.x, pieceptr[selpiece]->boxo.y);
SetDrMd(r, JAM2|INVERSVID); /*** Draw Corner "gadgets" */
SetBPen(r, 0L);
Move(r, pieceptr[selpiece]->boxo.x - 3L, pieceptr[selpiece]->boxo.y + 3L);
Text(r, "O", 1L);
Move(r, pieceptr[selpiece]->boxx.x - 3L, pieceptr[selpiece]->boxx.y + 3L);
Text(r, "x", 1L);
Move(r, pieceptr[selpiece]->boxz.x - 3L, pieceptr[selpiece]->boxz.y + 3L);
Text(r, " ", 1L);
Move(r, pieceptr[selpiece]->boxy.x - 3L, pieceptr[selpiece]->boxy.y + 3L);
Text(r, "y", 1L);
SetDrMd(r, JAM1);
SetWrMsk(r,0xFFFF);
}
/*===========================================================================*/
ToggleGhostBox() /* Draw or undraw current ghost box, as given in */
{ /* ghbox? variables, in COMPLEMENT mode */
SetDrMd(r, JAM1|COMPLEMENT);
Move(r, ghboxo.x, ghboxo.y);
Draw(r, ghboxx.x, ghboxx.y);
Draw(r, ghboxz.x, ghboxz.y);
Draw(r, ghboxy.x, ghboxy.y);
Draw(r, ghboxo.x, ghboxo.y);
SetDrMd(r, JAM1);
}
/*===========================================================================*/
ComputeNewBox() /* Compute New Ghost Box from mouse coords, put in tmpbox */
{ /* variables. */
long dx, dy; /* increments of mouse position from corner's previous pos */
double s, a; /* Scaling and Rotation components of change in vector Z */
double cosa, sina; /* cosine and sine of angle a */
double Qx, Qy;
double tmp;
switch (curcor) {
case 'o':
dx = mx - pieceptr[selpiece]->boxo.x;
dy = my - pieceptr[selpiece]->boxo.y;
tmpboxo.x = mx;
tmpboxo.y = my;
tmpboxx.x = pieceptr[selpiece]->boxx.x + dx;
tmpboxx.y = pieceptr[selpiece]->boxx.y + dy;
tmpboxy.x = pieceptr[selpiece]->boxy.x + dx;
tmpboxy.y = pieceptr[selpiece]->boxy.y + dy;
tmpboxz.x = pieceptr[selpiece]->boxz.x + dx;
tmpboxz.y = pieceptr[selpiece]->boxz.y + dy;
break;
case 'x':
dx = mx - pieceptr[selpiece]->boxx.x;
dy = my - pieceptr[selpiece]->boxx.y;
tmpboxo = pieceptr[selpiece]->boxo; /* Structure Assignment */
tmpboxx.x = mx;
tmpboxx.y = my;
tmpboxy = pieceptr[selpiece]->boxy; /* Structure Assignment */
tmpboxz.x = pieceptr[selpiece]->boxz.x + dx;
tmpboxz.y = pieceptr[selpiece]->boxz.y + dy;
break;
case 'y':
dx = mx - pieceptr[selpiece]->boxy.x;
dy = my - pieceptr[selpiece]->boxy.y;
tmpboxo = pieceptr[selpiece]->boxo; /* Structure Assignment */
tmpboxx = pieceptr[selpiece]->boxx; /* Structure Assignment */
tmpboxy.x = mx;
tmpboxy.y = my;
tmpboxz.x = pieceptr[selpiece]->boxz.x + dx;
tmpboxz.y = pieceptr[selpiece]->boxz.y + dy;
break;
case 'z':
s = sqrt((double)((mx-pieceptr[selpiece]->boxo.x)*
(mx-pieceptr[selpiece]->boxo.x)+(my-pieceptr[selpiece]->boxo.y)*
(my-pieceptr[selpiece]->boxo.y))/
(double)((pieceptr[selpiece]->boxz.x-pieceptr[selpiece]->boxo.x)*
(pieceptr[selpiece]->boxz.x-pieceptr[selpiece]->boxo.x)+
(pieceptr[selpiece]->boxz.y-pieceptr[selpiece]->boxo.y)*
(pieceptr[selpiece]->boxz.y-pieceptr[selpiece]->boxo.y)));
a = myatan2((double)(my - pieceptr[selpiece]->boxo.y), (double)(mx -
pieceptr[selpiece]->boxo.x)) - myatan2((double)
(pieceptr[selpiece]->boxz.y - pieceptr[selpiece]->boxo.y),
(double)(pieceptr[selpiece]->boxz.x - pieceptr[selpiece]->boxo.x));
cosa = cos(a);
sina = sin(a);
Qx = pieceptr[selpiece]->boxo.x + s * (pieceptr[selpiece]->boxo.y * sina -
pieceptr[selpiece]->boxo.x * cosa);
Qy = pieceptr[selpiece]->boxo.y - s * (pieceptr[selpiece]->boxo.y * cosa +
pieceptr[selpiece]->boxo.x * sina);
tmpboxo = pieceptr[selpiece]->boxo; /* Structure Assignment */
/* Below, the conditional assignments assure rounding on the */
/* double-to-int conversion rather than truncation */
tmp = s * (pieceptr[selpiece]->boxx.x * cosa -
pieceptr[selpiece]->boxx.y * sina) + Qx;
tmpboxx.x = (tmp - floor(tmp) > 0.5) ? tmp + 1. : tmp;
tmp = s * (pieceptr[selpiece]->boxx.x * sina +
pieceptr[selpiece]->boxx.y * cosa) + Qy;
tmpboxx.y = (tmp - floor(tmp) > 0.5) ? tmp + 1. : tmp;
tmp = s * (pieceptr[selpiece]->boxy.x * cosa -
pieceptr[selpiece]->boxy.y * sina) + Qx;
tmpboxy.x = (tmp - floor(tmp) > 0.5) ? tmp + 1. : tmp;
tmp = s * (pieceptr[selpiece]->boxy.x * sina +
pieceptr[selpiece]->boxy.y * cosa) + Qy;
tmpboxy.y = (tmp - floor(tmp) > 0.5) ? tmp + 1. : tmp;
tmpboxz.x = tmpboxy.x + tmpboxx.x - tmpboxo.x;
tmpboxz.y = tmpboxx.y + tmpboxy.y - tmpboxo.y;
break;
} /* End switch curcor */
}
/*===========================================================================*/
DeleteSelPiece() /* Delete the Selected Piece. If it was the only piece, */
{ /* replace it with a Default Piece. Rearrange Piece list */
FreePiece(pieceptr[selpiece]); /* free memory associated with the piece */
for (i = selpiece; i < N; i++) /* close gap in pointer array */
pieceptr[i] = pieceptr[i+1];
if (selpiece == N)
selpiece--;
N--;
if (N == -1) /* if deleted last piece, place a default piece */
AddDefPiece();
}
/*==========================================================================*/
ClearIFS() /* Clear IFS variables, memory, and Collage image */
{
/* Clear all GZZ bitplanes except Outline plane */
SetWrMsk(r,0xFFFD); /* Write-protect plane 1, Outline */
SetRast(r, 0L);
SetWrMsk(r,0xFFFF);
for(i = 0; i <= N; i++)
FreePiece(pieceptr[i]);
N = -1;
}
/*==========================================================================*/
HiliteGadget(gadgetid) /* frame gadget of given ID# in Red */
/* Implements in software Gadget Mutual Exclude */
/* Because window is GZZ and gadgets are in its border, this routine */
/* Draws the frame directly on the Screen,not in Window. It is quite */
/* non-generic because gadget coordinates are coded in numerically */
int gadgetid;
{
long i;
/*** Define frames as border structures ***/
static SHORT Frame_data[10] = { 0,0, 36,0, 36,15, 0,15, 0,0 };
/* Gadget select frame data */
static struct Border OnFrame_Bdr = { /* Red (Selected) Gadget border */
0,0, /* LeftEdge, TopEdge */
4,0,JAM1, /* FrontPen, BackPen, DrawMode */
5, /* Count */
Frame_data, /* XY */
NULL /* Next Border */
};
static struct Border OffFrame_Bdr = { /* Lt Green (deselected) Gadg border */
0,0, /* LeftEdge, TopEdge */
3,0,JAM1, /* FrontPen, BackPen, DrawMode */
5, /* Count */
Frame_data, /* XY */
NULL /* Next Border */
};
/*** Unframe all gadgets, then frame selected one */
for (i = 0; i <= 3; i++)
DrawBorder(scrp, &OffFrame_Bdr, 280L, i*18L+12L);
DrawBorder(scrp, &OnFrame_Bdr, 280L, gadgetid*18L+12L);
}
/*==========================================================================*/
DrawCollage() /* Draw the current IFS as a collage image with */
{ /* vector Box of Selected Piece (wipe out old box)*/
/*** Erase all bitplanes except Outline plane */
SetWrMsk(r,0xFFFD); /* Write-protect plane 1, Outline */
SetRast(r, 0L);
/* Blit Deselected pieces from piecemaps to plane 0 */
SetWrMsk(r,0x0001); /* Write protect all planes except plane 0 */
SetAPen(r, 1L);
for (i = 0; i <= N; i++)
if (i != selpiece) /* skip Selected piece */
BltTemplate((char*)pieceptr[i]->piecemap,(long)Window->BorderLeft,
(long)WIDTH/8, r, 0L, 0L, (long)GZZWIDTH, (long)GZZHEIGHT);
/* Blit Selected Piece from piecemap to plane 2 */
SetWrMsk(r,0x0004); /* Write protect all planes except plane 2 */
SetAPen(r, 4L);
BltTemplate((char*)pieceptr[selpiece]->piecemap,(long)Window->BorderLeft,
(long)WIDTH/8, r, 0L, 0L, (long)GZZWIDTH, (long)GZZHEIGHT);
DrawBox(); /* Draw Vector Box of Selected Piece */
/* Note that Rastport's WrMask is restored within DrawBox() */
}
/*==========================================================================*/
double myatan2(y,x) /* atan2() as defined in Aztec C but missing from mf.lib */
double x, y; /* returns arctangent of y/x in range -pi to pi. */
{ /* If x=y=0, returns 0, sets errno=EDOM. */
/* Requires #include of errno.h and math.h */
#define PI 3.141592654
if (x == 0.0) {
if (y == 0.0) {
errno = EDOM;
return(0.0);
}
else
x = 1.0e-10;
}
if (y >= 0.0) {
if (x >= 0.0)
return(atan(y/x)); /* Quadrant I */
else
return(PI - atan(-y/x)); /* Quadrant II */
}
else {
if (x >= 0.0)
return(-atan(-y/x)); /* Quadrant IV */
else
return(atan(y/x) - PI); /* Quadrant III */
}
}
/*==========================================================================*/
ModifyMousePtr(Wind, n)
/* Change to custom mouse pointer in Window if n=1, or restore default */
/* arrow and free CHIP RAM if n=-1. Use in only one window at a time! */
struct Window *Wind;
int n;
{
static short *ChipPtr;
static struct ViewPort *vprt;
static long color17, color18, color19;
long GetRGB4();
/*** Define Custom mouse pointer sprite data */
#define ROWS 14 /* Number of Pixel rows in pointer */
static USHORT Mouseptr[] = {
0x0000, 0x0000,
/* ++++++++++++++++++ */
0x00f0, 0x00f0, /* + 3333 + */
0x03f8, 0x03f8, /* + 3333333 + */
0x07fc, 0x079c, /* + 333311333 + */
0x0ffe, 0x0e0e, /* + 33311111333 + */
0x0ffe, 0x0c06, /* + 33111111133 + */
0xafff, 0x0c73, /* +1 1 331113331133+ */
0xafff, 0x0cfb, /* +1 1 331133333133+ */
0xafff, 0x0ccb, /* +1 1 331133113133+ */
0xcfff, 0x0cdb, /* +11 331133133133+ */
0xdfff, 0x18c3, /* +11 3311133111133+ */
0xffff, 0x1ce7, /* +1113331133311333+ */
0xfffe, 0x07fe, /* +111113333333333 + */
0x7ffe, 0x003c, /* + 11111111133331 + */
0x1fff, 0x0000, /* + 1111111111111+ */
/* ++++++++++++++++++ */
0x0000, 0x0000
};
if (n == 1 && ChipPtr == NULL) {
/*** Get colors of default pointer in Window's screen */
vprt = &(Wind->WScreen->ViewPort); /* ptr to viewport of screen */
color17 = GetRGB4(vprt->ColorMap, 17L);
color18 = GetRGB4(vprt->ColorMap, 18L);
color19 = GetRGB4(vprt->ColorMap, 19L);
/*** Copy sprite data into chip RAM to be accessible to graphic chips */
ChipPtr =(short*)AllocMem((long)((ROWS+2)*4),MEMF_CHIP); /* Alloc block */
CopyMem((char*)Mouseptr,(char*)ChipPtr,(long)((ROWS+2)*4)); /* Copy data*/
/*** Attach custom pointer to window */
SetPointer(Wind, ChipPtr, (long)ROWS, 16L, -1L, -1L);
/*** Change custom pointer colors */
SetRGB4(vprt, 17L, 15L, 12L, 10L);
SetRGB4(vprt, 18L, 13L, 2L, 2L);
SetRGB4(vprt, 19L, 15L, 0L, 0L);
}
else if (n == -1 && ChipPtr != NULL) {
ClearPointer(Wind); /* Reset default pointer and its original colors */
SetRGB4(vprt, 17L, color17>>8, (color17>>4L)&15, color17&15);
SetRGB4(vprt, 18L, color18>>8, (color18>>4L)&15, color18&15);
SetRGB4(vprt, 19L, color19>>8, (color19>>4L)&15, color19&15);
FreeMem(ChipPtr, (long)((ROWS+2)*4)); /* release memory of pointer data */
ChipPtr = NULL;
}
else
DisplayBeep(NULL); /* Illegal call (called twice in a row with same n */
}
/*===========================================================================*/
UpdateNumStrings() /* Update values of Coeff window string gadgets from */
{ /* selected piece structure. Redraw gadgets if the window is open */
double degr1, degr2;
degr1 = pieceptr[selpiece]->r1 / 0.017453293; /* convert radians to degrees*/
degr2 = pieceptr[selpiece]->r2 / 0.017453293;
sprintf((char*)NumNumT2coeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->f);
sprintf((char*)NumNumT1coeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->e);
sprintf((char*)NumNumR2coeffGadgSIBuff, "%5.lf", degr2);
sprintf((char*)NumNumR1coeffGadgSIBuff, "%5.lf", degr1);
sprintf((char*)NumNumS2coeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->s2);
sprintf((char*)NumNumS1coeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->s1);
sprintf((char*)NumNumPcoeffGadgSIBuff, "%5.3lf", pieceptr[selpiece]->p);
sprintf((char*)NumNumDenscoeffGadgSIBuff,"%4.1lf", pieceptr[selpiece]->dens);
sprintf((char*)NumNumFcoeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->f);
sprintf((char*)NumNumEcoeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->e);
sprintf((char*)NumNumDcoeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->d);
sprintf((char*)NumNumCcoeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->c);
sprintf((char*)NumNumBcoeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->b);
sprintf((char*)NumNumAcoeffGadgSIBuff, "%5.2lf", pieceptr[selpiece]->a);
if (exists_numwindow)
RefreshGadgets(&NumGadgetList3, NumWindow, NULL);
}
/*===========================================================================*/
RecomputeCoeffs(gadgetid) /* Re-Calculate 13 coefficients based on */
int gadgetid; /* change in value of the one in the string gadget with */
{ /* the given gadgetid; put new values in string gadgets */
/* Does range checking on entered coefficients; If user */
/* entered an illegal value, will restore previous */
/* value and inform user before returning. */
double a, b, c, d, e, f, s1, s2, r1, r2, t1, t2, dens, p;
double sum, p0, det, olddet, olddens;
/* Put current coefficient values into temporary variables */
sscanf((char*)NumNumT2coeffGadgSIBuff, "%lf", &t2);
sscanf((char*)NumNumT1coeffGadgSIBuff, "%lf", &t1);
sscanf((char*)NumNumR2coeffGadgSIBuff, "%lf", &r2);
sscanf((char*)NumNumR1coeffGadgSIBuff, "%lf", &r1);
sscanf((char*)NumNumS2coeffGadgSIBuff, "%lf", &s2);
sscanf((char*)NumNumS1coeffGadgSIBuff, "%lf", &s1);
sscanf((char*)NumNumPcoeffGadgSIBuff, "%lf", &p);
sscanf((char*)NumNumDenscoeffGadgSIBuff, "%lf", &dens);
sscanf((char*)NumNumFcoeffGadgSIBuff, "%lf", &f);
sscanf((char*)NumNumEcoeffGadgSIBuff, "%lf", &e);
sscanf((char*)NumNumDcoeffGadgSIBuff, "%lf", &d);
sscanf((char*)NumNumCcoeffGadgSIBuff, "%lf", &c);
sscanf((char*)NumNumBcoeffGadgSIBuff, "%lf", &b);
sscanf((char*)NumNumAcoeffGadgSIBuff, "%lf", &a);
while (r1 > 180. || r1 < -180.) /* Get angles to range -180 => +180 */
r1 = (r1 > 0.) ? r1 - 360. : r1 + 360.;
while (r2 > 180. || r2 < -180.)
r2 = (r2 > 0.) ? r2 - 360. : r2 + 360.;
r1 = r1*0.017453293; /* convert degrees to radians*/
r2 = r2*0.017453293;
/*** Check that all coefficients are in legal ranges */
if (a < -1. || a > 1. || b < -1. || b > 1. || c < -1. || c > 1. ||
d < -1. || d > 1. || e < -0.25 || e > 1. || f < -0.25 || f > 1. ||
s1 < -1. || s1 > 1. || s2 < -1. || s2 > 1. || dens <= 0. ||
t1 < -0.25 || t1 > 1. || t2 < -0.25 || t2 > 1. || p <= 0. || p > 1.) {
ShowError("Coefficient out of Range!");
a = pieceptr[selpiece]->a; /*** Undo the error */
b = pieceptr[selpiece]->b;
c = pieceptr[selpiece]->c;
d = pieceptr[selpiece]->d;
e = pieceptr[selpiece]->e;
f = pieceptr[selpiece]->f;
p = pieceptr[selpiece]->p;
dens = pieceptr[selpiece]->dens;
s1 = pieceptr[selpiece]->s1;
s2 = pieceptr[selpiece]->s2;
r1 = pieceptr[selpiece]->r1;
r2 = pieceptr[selpiece]->r2;
t1 = pieceptr[selpiece]->e;
t2 = pieceptr[selpiece]->f;
}
det = fabs(a * d - b * c);
if (det == 0.0)
det = 0.01;
sum = -(pieceptr[selpiece]->dens * pieceptr[selpiece]->det) + dens * det;
for (i = 0; i <= N; i++)
sum = sum + pieceptr[i]->dens * pieceptr[i]->det;
if (gadgetid <= 26) { /* id's 21 thru 26, matrix coeffs a - f */
s1 = sqrt(a*a + c*c);
s2 = sqrt(b*b + d*d);
r1 = myatan2(c, a);
r2 = myatan2(-b, d);
t1 = e;
t2 = f;
p = (dens * det)/sum;
}
if (gadgetid == 27) { /* density coefficient */
p = (dens * det)/sum;
}
if (gadgetid == 28) { /* probability coefficient */
olddens = dens;
p0 = det / (sum - olddens*det + det); /* What p SHOULD be with dens == 1 */
dens = p / p0;
p = (dens * det)/(sum - olddens*det + dens*det);
}
if (gadgetid >= 29) { /* id's 29 thru 34, geometrical coeffs s1 thru t2 */
olddet = fabs(a * d - b * c);
if (olddet == 0.0)
olddet = 0.01;
a = s1 * cos(r1);
b = -s2 * sin(r2);
c = s1 * sin(r1);
d = s2 * cos(r2);
e = t1;
f = t2;
det = fabs(a * d - b * c); /*** recompute det and probability */
if (det == 0.0)
det = 0.01;
sum = sum - olddet*dens + det*dens;
p = (dens * det)/sum;
}
r1 = r1 / 0.017453293; /* convert radians to degrees */
r2 = r2 / 0.017453293;
/* Put resultant coefficient values into their string gadgets */
sprintf((char*)NumNumT2coeffGadgSIBuff, "%5.2lf", f);
sprintf((char*)NumNumT1coeffGadgSIBuff, "%5.2lf", e);
sprintf((char*)NumNumR2coeffGadgSIBuff, "%5.lf", r2);
sprintf((char*)NumNumR1coeffGadgSIBuff, "%5.lf", r1);
sprintf((char*)NumNumS2coeffGadgSIBuff, "%5.2lf", s2);
sprintf((char*)NumNumS1coeffGadgSIBuff, "%5.2lf", s1);
sprintf((char*)NumNumPcoeffGadgSIBuff, "%5.3lf", p);
sprintf((char*)NumNumDenscoeffGadgSIBuff, "%4.1lf", dens);
sprintf((char*)NumNumFcoeffGadgSIBuff, "%5.2lf", f);
sprintf((char*)NumNumEcoeffGadgSIBuff, "%5.2lf", e);
sprintf((char*)NumNumDcoeffGadgSIBuff, "%5.2lf", d);
sprintf((char*)NumNumCcoeffGadgSIBuff, "%5.2lf", c);
sprintf((char*)NumNumBcoeffGadgSIBuff, "%5.2lf", b);
sprintf((char*)NumNumAcoeffGadgSIBuff, "%5.2lf", a);
return;
}
/*==========================================================================*/
ShowError(text) /* Show error message in a Window, return on user */
/* clicking in the OK gadget. Text string must not */
/* exceed Window's width minus two characters. */
/* Window is used and not a requester so it is in front */
/* of coeffs window & GZZ Border of main Window */
char *text; /* The message to be displayed */
{
struct Message * GetMsg();
void ReplyMsg();
struct IntuiMessage *message;
int gadgetid;
struct Window *ErrWindow, *OpenWindow();
#define TEXTCOLOR 3 /* Text color for message and "OK" */
#define BGCOLOR 14 /* Color for Window and Gadget background */
#define GADGBDRCOLOR 3 /* Color for border of "OK" Gadget */
#define BDRCOLOR 3 /* Color for border of Error-window */
/*** Initialize Error-window structures */
static struct IntuiText OKGadgetMsg = {
TEXTCOLOR, BGCOLOR, /* FrontPen, BackPen */
JAM1, /* DrawMode */
4,3, /* LeftEdge, TopEdge */
NULL, /* ITextFont */
(UBYTE*)"OK", /* IText */
NULL /* NextText */
};
static SHORT OKGadgetCoord[18] = { 0,0, 23,0, 23,12, 0,12, 0,0,
24,0, 24,12, -1,12, -1,0 };
/* NOTE: Second line above gives 2-pixel-wide border for hires screen */
static struct Border OKGadgetBdr = {
0,0, /* LeftEdge, TopEdge */
GADGBDRCOLOR, BGCOLOR, JAM1, /* FrontPen, BackPen, DrawMode */
9, /* Count */
&OKGadgetCoord[0], /* XY */
NULL /* NextBorder */
};
static struct Gadget OKGadget = {
NULL, /* NextGadget */
-40,35,24,13, /* LeftEdge, TopEdge, Width, Height */
GADGHCOMP | GRELRIGHT, /* Flags */
ENDGADGET |
RELVERIFY, /* Activation */
BOOLGADGET, /* GadgetType */
(APTR)&OKGadgetBdr, /* GadgetRender */
NULL, /* SelectRender */
&OKGadgetMsg, /* GadgetText */
0, /* MutualExclude */
NULL, /* SpecialInfo */
99, /* GadgetID */
NULL /* UserData */
};
static SHORT BdrCoords[10] = { 2,2, 0,2, 0,57, 2,57, 2,2 };
/* 0's to be replaced later */
static struct Border Bdr = {
0, 0, /* LeftEdge, TopEdge */
BDRCOLOR, BGCOLOR, JAM1, /* FrontPen, BackPen, DrawMode */
5, /* Count */
&BdrCoords[0], /* XY */
NULL /* NextBorder */
};
static struct IntuiText ErrText = {
TEXTCOLOR, BGCOLOR, JAM1, /* FrontPen, BackPen, DrawMode */
8, 18, /* LeftEdge, TopEdge */
NULL, /* ITextFont */
NULL, /* IText -- Will be filled later */
NULL, /* NextText */
};
static struct Image ErrWinBgnd = { /* Just a filled rectangle */
0, 0, /* LeftEdge, TopEdge */
0, 60, 0, /* Width,Height, Depth */
NULL, /* ImageData */
0x0, 0xE, /* PlanePick, PlaneOnOff */
NULL /* NextImage */
};
static struct NewWindow ErrNewWindow = {
0,60, /* window XY origin relative to TopLeft of screen */
0,60, /* window width and height */
TEXTCOLOR,BDRCOLOR, /* detail and block pens */
GADGETUP, /* IDCMP flags */
ACTIVATE|SIMPLE_REFRESH|BORDERLESS, /* other window flags */
&OKGadget, /* first gadget in gadget list */
NULL, /* custom CHECKMARK imagery */
NULL, /* window title */
NULL, /* custom screen pointer */
NULL, /* custom bitmap */
5,5, /* minimum width and height */
-1,-1, /* maximum width and height */
CUSTOMSCREEN /* destination screen type */
};
/*** Compute and fill in text and window-dependent stuff */
ErrNewWindow.Screen = Screen;
ErrNewWindow.Width = strlen(text) * 8 + 16;
if (ErrNewWindow.Width < 44)
ErrNewWindow.Width = 44;
ErrWinBgnd.Width = ErrNewWindow.Width;
ErrNewWindow.LeftEdge = (320 - ErrNewWindow.Width)/2;
if (ErrNewWindow.LeftEdge < 0)
ErrNewWindow.LeftEdge = 0;
BdrCoords[2] = BdrCoords[4] = ErrNewWindow.Width - 3;
ErrText.IText = (UBYTE*)text;
if (Window->WScreen->Width = 320) /* If Lo-res -- remove vert. double line */
OKGadgetBdr.Count = 5;
else
OKGadgetBdr.Count = 9;
/*** Display the Error-Window */
if ((ErrWindow = OpenWindow(&ErrNewWindow)) == NULL) {
printf("\nCouldn't open Error Message window!!!\n");
CloseAll();
}
DrawImage(ErrWindow->RPort, &ErrWinBgnd, 0L, 0L);
PrintIText(ErrWindow->RPort, &ErrText, 0L, 0L);
DrawBorder(ErrWindow->RPort, &Bdr, 0L, 0L);
RefreshGadgets(&OKGadget, ErrWindow, NULL);
/* Because DrawImage() obscured the OK Gadget image */
/*** Wait until user clicks the Error-window's "OK" Gadget */
gadgetid = 9999;
while (gadgetid != 99) {
if (message = (struct IntuiMessage *)GetMsg(ErrWindow->UserPort)) {
gadgetid = ((struct Gadget *)(message->IAddress))->GadgetID;
ReplyMsg(message);
}
}
CloseWindow(ErrWindow);
}
/*===========================================================================*/
OpenImageScreen(width, height, depth) /* Open a Custom screen & window for */
/* the Image; Set exists_image flag */
int width, height, depth;
{
struct NewScreen ns;
struct Screen *OpenScreen();
struct NewWindow nw;
struct Window *OpenWindow();
long numcols; /* # of colors in screen */
UWORD *colortableptr[5]; /* Array of Pointers to screen colortables */
/* Note: element 0 is not used! */
static UWORD colortable1[] = /*** Colors for 1-bitplane screen */
{0x000, 0x068, 0x0AF, 0x5CF};
static UWORD colortable2[] = /*** Colors for 2-bitplane screen */
{0x000, 0x057, 0x07B, 0xAF};
static UWORD colortable3[] = /*** Colors for 3-bitplane screen */
{0x000, 0x034, 0x046, 0x068, 0x06A, 0x08C, 0x09E, 0x0AF};
static UWORD colortable4[] = /*** Colors for 4-bitplane screen */
{0x000, 0x011, 0x012, 0x023, 0x034, 0x045, 0x046, 0x057,
0x068, 0x069, 0x06A, 0x07B, 0x08C, 0x08D, 0x09E, 0x0AF};
colortableptr[1] = colortable1;
colortableptr[2] = colortable2;
colortableptr[3] = colortable3;
colortableptr[4] = colortable4;
ns.LeftEdge = 0; /*** Initialize NewScreen structure */
ns.TopEdge = 0;
ns.Width = width;
ns.Height = height;
ns.Depth = (depth == 1) ? 2 : depth;
ns.DetailPen = 3; /* Colour of text in screen title bar */
ns.BlockPen = 1; /* Colour of screen Title Bar */
ns.ViewModes = ((width == 640) ? HIRES:0) | ((height == 400) ? INTERLACE:0);
ns.Type = CUSTOMSCREEN;
ns.Font = &TOPAZ80;
ns.DefaultTitle = (UBYTE*)" Click in screen to stop rendering";
ns.Gadgets = NULL;
ns.CustomBitMap = NULL;
switch (depth) { /* Customize Image Title and Border colors to depth */
case (1):
ns.DetailPen = 3;
ns.BlockPen = 1;
break;
case (2):
ns.DetailPen = 3;
ns.BlockPen = 1;
break;
case (3):
ns.DetailPen = 7;
ns.BlockPen = 3;
break;
case (4):
ns.DetailPen = 15;
ns.BlockPen = 7;
break;
}
nw.LeftEdge = 0; /*** Initialize NewWindow structure */
nw.TopEdge = 0;
nw.Width = width;
nw.Height = height;
nw.DetailPen = ns.DetailPen; /* Title text color */
nw.BlockPen = ns.BlockPen; /* Title bar background */
nw.IDCMPFlags = MOUSEBUTTONS;
nw.Flags = ACTIVATE|GIMMEZEROZERO|SIMPLE_REFRESH|BACKDROP;
nw.FirstGadget = NULL;
nw.CheckMark = NULL;
nw.Title = (UBYTE*)" "; /* Never seen - stays behind screen title bar */
nw.Screen = NULL; /* Will set it to ImageScreen after the screen is opened */
nw.BitMap = NULL;
nw.MinWidth = 0;
nw.MinHeight = 0;
nw.MaxWidth = 0;
nw.MaxHeight = 0;
nw.Type = CUSTOMSCREEN;
/*** Open the screen */
if ((ImageScreen = (struct Screen *) OpenScreen(&ns)) == NULL) {
ShowError("Couldn't open Image screen!");
return;
}
/* Link Custom colours defined above to screen's ViewPort */
numcols = 1 << ns.Depth;
LoadRGB4(&(ImageScreen->ViewPort), colortableptr[depth], numcols);
/*** Open the Window */
nw.Screen = ImageScreen;
if ((ImageWindow = (struct Window *) OpenWindow(&nw)) == NULL) {
CloseScreen(ImageScreen);
ShowError("Couldn't open Image window!");
return;
}
SetWindowTitles(ImageWindow,-1L,
(char *)" Click in screen to stop rendering");
exists_image = 1;
}
/*===========================================================================*/
CloseImageScreen() /* Close image screen & Window, reset exists_image flag */
{
struct Message * GetMsg();
void ReplyMsg();
struct IntuiMessage *message;
/* Empty ImageWindow IDCMP queue if any */
while (message = (struct IntuiMessage *)GetMsg(ImageWindow->UserPort))
ReplyMsg(message);
CloseWindow(ImageWindow);
CloseScreen(ImageScreen);
exists_image = 0;
}
/*===========================================================================*/
DoDemo() /* Demonstrate IFS process, then NEW and return */
{
if (SetMode(OUTLINE) == 1) {
SetRast(r, 0L);
exists_outline = 0;
}
else /* User clicked CANCEL in IFS WILL BE LOST requester - Abort demo */
return;
ModifyIDCMP(Window, NULL); /* Disable Editor Window IDCMP during Demo */
ClearMenuStrip(Window); /* remove main window menus during demo */
AboutText(DEMOTEXT); /* Show explanation of demo in text screen */
ModifyMousePtr(Window, 1); /* Bring up 'ZZ' pointer */
/* Draw outline of Sierpinski Triangle */
SetDrMd(r, JAM1);
for (i = 0; i < 100000; i++) ; /* Delay */
Move(r, 138L, 24L);
Draw(r, 24L, 172L);
for (i = 0; i < 100000; i++) ; /* Delay */
Draw(r, 238L, 131L);
for (i = 0; i < 100000; i++) ; /* Delay */
Draw(r, 138L, 24L);
for (i = 0; i < 100000; i++) ; /* Delay */
Move(r, 82L, 98L);
Draw(r, 188L, 77L);
for (i = 0; i < 100000; i++) ; /* Delay */
Draw(r, 130L, 152L);
for (i = 0; i < 100000; i++) ; /* Delay */
Draw(r, 82L, 98L);
exists_outline = 1;
for (i = 0; i < 150000; i++) /* Delay before entering Collage Editor */
;
/*** Place 3 Pieces to form Collage */
SetMode(COLLAGE);
for (i = 0; i < 100000; i++) ; /* Delay */
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
AddDefPiece();
DrawCollage();
pieceptr[0]->e = 0.25;
pieceptr[0]->f = 0.045;
pieceptr[0]->dens = 1.0;
ComputeBoxCorners(pieceptr[0]);
ComputeProbs();
for (i = 0; i < 100000; i++) ; /* Delay */
TransformPiece(outlinebufptr, pieceptr[0]->piecemap, pieceptr[0]);
DrawCollage();
for (i = 0; i < 100000; i++) ; /* Delay */
AddDefPiece();
DrawCollage();
pieceptr[1]->e = 0.045;
pieceptr[1]->f = 0.315;
pieceptr[1]->dens = 0.4;
ComputeBoxCorners(pieceptr[1]);
ComputeProbs();
for (i = 0; i < 100000; i++) ; /* Delay */
TransformPiece(outlinebufptr, pieceptr[1]->piecemap, pieceptr[1]);
DrawCollage();
for (i = 0; i < 100000; i++) ; /* Delay */
AddDefPiece();
DrawCollage();
pieceptr[2]->e = 0.43;
pieceptr[2]->f = 0.24;
pieceptr[2]->dens = 0.7;
ComputeBoxCorners(pieceptr[2]);
ComputeProbs();
for (i = 0; i < 100000; i++) ; /* Delay */
TransformPiece(outlinebufptr, pieceptr[2]->piecemap, pieceptr[2]);
DrawCollage();
for (i = 0; i < 300000; i++) /* Delay before rendering */
;
RenderImage(0); /* Render, until user clicks in image screen */
/*** After rendering ended, do a NEW (without IFS WILL BE LOST requester) */
ClearIFS();
RemoveGList(Window, &CollageGadgetList2, 6L);
AddGList(Window, &GadgetList1, 0L, 6L, NULL); /* change gadgets */
SetDrMd(scrp, JAM1);
SetAPen(scrp, 0L);
RectFill(scrp, 280L, 12L, 316L, 117L); /* Blot out old gadget images */
RefreshGadgets(&GadgetList1, Window, NULL);
OffMenu(Window, NOITEM<<5 | 2); /* disable render menu and its items */
SetWindowTitles(Window, -1L, " Outline Editor");
drawmode = FREEHAND;
HiliteGadget(0);
SetAPen(r, 2L);
SetRast(r, 0L);
exists_outline = 0;
CloseImageScreen();
ModifyIDCMP(Window, MOUSEBUTTONS|GADGETUP|MENUPICK); /* Restore IDCMP */
SetMenuStrip(Window, &MenuList1); /* Restore menu strip */
}
/*===========================================================================*/
ComputeBoxCorners(pcptr) /* Compute Vector Box corners from Piece coeffs */
struct piece *pcptr;
{
pcptr->boxo.x = pcptr->e * GZZWIDTH;
pcptr->boxo.y = pcptr->f * GZZWIDTH; /* sic! */
pcptr->boxx.x = (pcptr->a + pcptr->e) * GZZWIDTH;
pcptr->boxx.y = (pcptr->c + pcptr->f) * GZZWIDTH;
pcptr->boxy.x = (pcptr->b*GZZHEIGHT/GZZWIDTH + pcptr->e) * GZZWIDTH;
pcptr->boxy.y = (pcptr->d*GZZHEIGHT/GZZWIDTH + pcptr->f) * GZZWIDTH;
pcptr->boxz.x = pcptr->boxy.x + pcptr->boxx.x - pcptr->boxo.x;
pcptr->boxz.y = pcptr->boxy.y + pcptr->boxx.y - pcptr->boxo.y;
}
/*===========================================================================*/
LoadILBM(fnam, dest) /* Load an Image from IFF file; If dest = 1, */
char *fnam; /* put image and colormap in Image Screen; */
int dest; /* if dest = 0, put plane 0 of image in Outline */
{
struct BitMap picbitmap = {0}; /* Empty BitMap structure to "Fill" */
ILBMFrame iFrame; /* ILBM Frame to be used by Reader Routines */
LONG file; /* File handle [we use AmigaDOS Open(), not Manx open()] */
LONG iffp;
char *blitbuffer; /* Needed for the Blit operation only */
struct BitMap tmpbitmap; /* used for 2-step blit to Outline */
#define MIN(a,b) ((a)<(b)?(a):(b))
/* Open the File to read */
if ((file = Open(fnam, MODE_OLDFILE)) == NULL) {
ShowError("Can't open file!");
return;
}
ModifyMousePtr(Window, 1); /* Bring up 'ZZ' pointer */
/* Use EA IFF routine ReadPicture() to Read image from ILBM file into */
/* memory, modify picbitmap accordingly */
iffp = ReadPicture(file,&picbitmap,&iFrame,ChipAlloc);
Close(file);
if (iffp != IFF_DONE) { /* React to error message from EA routine, if any */
ShowError(IFFPMessages[-iffp]);
if (picbitmap.Planes[0]) /* free planes allocated by ReadPicture, if any */
RemFree(picbitmap.Planes[0]);
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
return;
}
/*** Now image is in memory; copy it to the proper destination bitmap */
switch (dest) {
case 0: /*** Copy plane 0 of loaded image to Outline (plane 1 in Window) */
SetRast(r, 0L); /* Erase old outline, set drawmode to FREEHAND */
if(drawmode == ERASE || drawmode == FILL) {
drawmode = FREEHAND;
SetAPen(r,2L);
HiliteGadget(0);
}
/* NOTE: Must use 2 steps because must blit (possibly part of) loaded */
/* image of arbitrary size, adjusting for GZZ borders, and from plane 0 */
/* to plane 1. Neither BltBitMap nor BltTemplate can do this in 1 step */
/* Step 1: Blit plane 0 of loaded image to temp bitmap */
/* (uses outline buffer as its single bitplane) */
InitBitMap(&tmpbitmap, 1L, WIDTH, HEIGHT);
tmpbitmap.Planes[0] = (PLANEPTR)outlinebufptr;
blitbuffer = (char *)AllocMem(80L,MEMF_CHIP); /* Allocate temp buffer */
BltBitMap(&picbitmap, 0L, 0L, &tmpbitmap, 0L, 0L,
MIN(WIDTH, picbitmap.BytesPerRow*8L),
MIN(HEIGHT, picbitmap.Rows), 192L, 0x1, blitbuffer);
/* 192L is minterm for Direct Copy; 0x1 is mask, will copy plane 0 */
FreeMem(blitbuffer, 80L);
/* Step 2: Blit the temporary bitplane from Outline Buffer to plane 1 */
/* of GZZ Window */
SetAPen(r, 2L);
SetDrMd(r, JAM1);
SetWrMsk(r,0x0002); /* Write protect all planes except plane 1 */
BltTemplate((char*)outlinebufptr, 0L, WIDTH/8L, Window->RPort, 0L, 0L,
MIN(GZZWIDTH, picbitmap.BytesPerRow*8L), MIN(GZZHEIGHT, picbitmap.Rows));
SetWrMsk(r,0xFFFF);
exists_outline = 1;
break;
case 1: /*** Set up a (new) Image Screen and blit loaded image into it */
if (exists_image)
CloseImageScreen();
OpenImageScreen(iFrame.bmHdr.pageWidth, iFrame.bmHdr.pageHeight,
picbitmap.Depth);
/* Link colours read in from file to screen's ViewPort */
LoadRGB4(&(ImageScreen->ViewPort), iFrame.colorMap, 1<<picbitmap.Depth);
SetWindowTitles(ImageWindow,
(char *)" ", (char *)" Click in screen to push it back");
blitbuffer = (char *)AllocMem(80L,MEMF_CHIP); /* Allocate temp buffer */
BltBitMap(&picbitmap, 2L, 11L, ImageWindow->RPort->BitMap, 2L, 11L,
MIN(ImageWindow->Width-4L,picbitmap.BytesPerRow*8L-2L),
MIN(ImageWindow->Height-13L,picbitmap.Rows-11L), 192L, 0xFF, blitbuffer);
/* 192L is minterm for Direct Copy; 0xFF is mask, will copy all planes */
/* 2L, 11L, 4L, 13L cause The blit to skip the window borders */
FreeMem(blitbuffer, 80L);
exists_image = 1;
break;
} /* End switch dest */
if (picbitmap.Planes[0]) /* free planes allocated by ReadPicture, if any */
RemFree(picbitmap.Planes[0]);
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
}
/*==========================================================================*/
AboutText(whichtext) /* Opens the text screen and displays in it */
int whichtext; /* the selected About text or IFS code table */
/* according to whichtext. Closes on click in screen */
/* whichtext can be: CODES, IFS_THEORY, HELP1, HELP2, AUTHOR, DEMOTEXT*/
{
struct Screen *TextScreen;
struct Window *TextWindow;
struct NewScreen ns;
struct Screen *OpenScreen();
struct NewWindow nw;
struct Window *OpenWindow();
struct Message * GetMsg();
struct IntuiMessage *message;
static struct IntuiText RedText = {
3, 0, JAM1, /* FrontPen, BackPen, DrawMode */
0, 0, /* LeftEdge, TopEdge */
&TOPAZ80, /* ITextFont */
(UBYTE*)"Click Mouse to Continue", NULL /* IText, NextText */
};
char codelinebuf[78]; /* Buffer for line of codes in CODES display */
static struct IntuiText CodesText = { /* Codes line for display */
1, 0, JAM1, /* FrontPen, BackPen, DrawMode */
0, 0, /* LeftEdge, TopEdge */
&TOPAZ80, /* ITextFont */
NULL, NULL /* IText, NextText */
};
/*** Open a window in a custom Hires screen for text display */
ns.LeftEdge = 0; /*** Initialize NewScreen structure */
ns.TopEdge = 0;
ns.Width = 640;
ns.Height = 200;
ns.Depth = 2;
ns.DetailPen = 0; /* Colour of text in screen title bar */
ns.BlockPen = 1; /* Colour of screen Title Bar */
ns.ViewModes = HIRES;
ns.Type = CUSTOMSCREEN;
ns.Font = &TOPAZ80;
ns.DefaultTitle = NULL;
ns.Gadgets = NULL;
ns.CustomBitMap = NULL;
nw.LeftEdge = 0; /*** Initialize NewWindow structure */
nw.TopEdge = 0;
nw.Width = 640;
nw.Height = 200;
nw.DetailPen = 0; /* Menu title text color */
nw.BlockPen = 1; /* Menu item box and title bar background */
nw.IDCMPFlags = MOUSEBUTTONS;
nw.Flags = ACTIVATE|SIMPLE_REFRESH;
nw.FirstGadget = NULL;
nw.CheckMark = NULL;
nw.Title = (UBYTE*)" ";
nw.Screen = NULL; /* Will set it to TextScreen after the screen is opened */
nw.BitMap = NULL;
nw.MinWidth = 0;
nw.MinHeight = 0;
nw.MaxWidth = 0;
nw.MaxHeight = 0;
nw.Type = CUSTOMSCREEN;
/*** Open the screen */
if ((TextScreen = (struct Screen *) OpenScreen(&ns)) == NULL) {
ShowError("Couldn't open Text screen!!!");
return;
}
/*** Open the Window */
nw.Screen = TextScreen;
if ((TextWindow = (struct Window *) OpenWindow(&nw)) == NULL) {
CloseScreen(TextScreen);
ShowError("Couldn't open Text window!!!");
return;
}
Textrp = (TextWindow->RPort); /* Window's rastport, used by p() */
p(NULL); /* reset screen print routine to top of screen */
p(" "); /* skip 2 lines to clear text window title bar */
p(" ");
switch (whichtext) { /**** Print appropreiate text into window */
case IFS_THEORY:
SetWindowTitles(TextWindow, " IFS Theory Background", -1L);
p(" IFS is a method developed by Michael F. Barnsley that allows one to en\
code a");
p(" Fractal as a small set of numbers, the coefficients of an Iterated Funct\
ion");
p(" System (IFS) Code, and later to reconstruct it from those numbers. An IF\
S Code");
p(" is a set of Contractive Affine Transformations, which are transformation\
s of");
p(" the plane that combine a Linear Transformation (consisting of combinatio\
ns of");
p(" stretching and rotation) and a Translation of the origin. Each such affi\
ne");
p(" transformation can be represented by six real numbers. In addition, with\
each");
p(" transformation is associated a probability value.");
p(" ");
p(" To derive the IFS Code for a given Fractal image, one must find a set \
of");
p(" transformations of the image - reduced, deformed copies of it - that whe\
n");
p(" taken together cover the original image. To reconstruct the image, one \
starts");
p(" with any point in the plane, picks at random one of the transformations");
p(" defined above, applies it to the point, and draws the resulting point. T\
o this");
p(" new point one applies the same procedure, and so on. The probabilities d\
efine");
p(" how often each transformation will be picked. The 'Collage Theorem' assu\
res");
p(" that this process will in fact reconstruct the original Fractal.");
p(" ");
p(" For more detailed information on the theory and use of IFS, refer to:");
p(" - Barnsley and Sloan: A Better Way to Compress Images, BYTE, Jan. 88\
.");
p(" - Peitgen and Saupe, eds.: The Science of Fractal Images, Chapter 5.");
break;
case HELP1:
SetWindowTitles(TextWindow, " A Summary of Program Operation", -1L);
p(" This program requires two steps to generate an IFS Code for a Fractal:");
p(" ");
p(" a. OUTLINE EDITOR: This step allows you to draw the approximate Outline \
of");
p(" the planned Fractal. The user interface is a simple Paint program, with");
p(" Freestyle, Lines, Erase (XXX), Fill and Clear gadgets. Note that the le\
ss");
p(" pixels you draw, the faster things will move later, in the Collage Edit\
or");
p(" phase. When your Outline is finished, click DONE to enter the Collage E\
ditor.");
p(" ");
p(" b. COLLAGE EDITOR: Here you create the Collage, by defining the affine");
p(" transformations ('Pieces') to cover the Outline with. When you enter th\
is");
p(" mode, you see your Outline, and one Default transformation - a half-siz\
ed");
p(" copy of this Outline, drawn in red. The box around it is the image of t\
he");
p(" screen boundary under the transformation. You can modify the Piece by");
p(" dragging any corner of this box with the mouse. The corner marked 'O' w\
ill");
p(" translate the Origin; 'X' and 'Y' will stretch and rotate these axes; T\
he");
p(" last corner will enlarge and rotate the Piece without deforming it. Cli\
ck");
p(" ADD to add a new Default Piece, or DUP to add a duplicate of the curren\
t");
p(" Piece. The Piece drawn in red is the 'Selected' one; all editing action\
s");
p(" apply to it. Clicking SEL repeatedly will make one Piece after another \
the");
p(" Selected one, allowing you to modify (or delete, by clicking DEL) previ\
ously");
p(" defined Pieces.");
break;
case HELP2:
SetWindowTitles(TextWindow, " A Summary of Program Operation (Continued)",
-1L);
p(" You can click the NUM gadget to get a numeric display of the Selected");
p(" transformation's coefficients (a-f, p), as well as the associated Proba\
bility");
p(" Density (probability per unit area) and Scalings, Rotations and Transla\
tions.");
p(" You can modify any one of these values in their string gadgets, and cli\
ck");
p(" ENTER to make the changes take effect. To quit the numeric window, clic\
k its");
p(" Close gadget.");
p(" ");
p(" When you've covered the Outline fully with Pieces, use the Render men\
u");
p(" to generate the Attractor of the IFS in the resolution and gray level c\
ount");
p(" of your choice.");
p(" ");
p(" The Optimize menu item will modify the current IFS so that its Attrac\
tor");
p(" will fill the screen; it will also generate an exact Collage for it, by\
using");
p(" the Attractor itself as an Outline.");
p(" ");
p(" File I/O menuitems allow you to save the IFS codes or the Image to d\
isk,");
p(" to load IFS Codes from files saved by IFSLab and by most other IFS prog\
rams,");
p(" and to load any Non-HAM IFF image file into the Image screen or as the");
p(" Outline.");
break;
case AUTHOR:
SetWindowTitles(TextWindow, " Author Information", -1L);
p(" ");
p(" ");
p(" ");
p(" ");
p(" IFS Lab written by Nathan Zeldes");
p(" ");
p(" ");
p(" Copyright (C) 1992 by N. Zeldes. All Rights Reserved. ");
p(" ");
p(" Thanks to C.W. Fox and Bruce Dawson for the File Requester");
p(" ");
p(" ");
p(" ");
p(" ");
p(" ");
p(" ");
break;
case DEMOTEXT:
SetWindowTitles(TextWindow, " A Demonstration of IFS in Action", -1L);
p(" ");
p(" This demo will define and render the Sierpinski Triangle, a well known");
p(" fractal.");
p(" ");
p(" The program will first enter the Outline Editor and draw an Outline of\
the");
p(" Sierpinski triangle. After a brief delay it will switch to the Collage E\
ditor");
p(" and show how the Outline can be covered by three half-sized copies of it\
self.");
p(" When it has built this Collage, the program will initiate rendering of t\
he");
p(" fractal. Note that this demo intentionally assigns unequal probabilities\
to");
p(" the three transformations, which causes the uneven 'shading' effect in t\
he");
p(" rendered image.");
p(" ");
p(" To start the demo, click the left mouse button. Do no more until the");
p(" rendering begins. When you've had your fill of the beauty of the emergin\
g");
p(" image, click twice in the Image screen to exit the demo.");
break;
case CODES: /* Display Codes Table */
SetWindowTitles(TextWindow, " IFS Code Coefficients", -1L);
p(" A B C D E F P Dens S1 S2\
R1 R2 ");
if (N < MAX_N)
p(" ------ ------ ------ ------ ----- ----- ----- ------- ----- -----\
----- ----- "); /* The underline is omitted to allow display of 20 pieces */
for(i = 0; i <= N; i++) { /* Put lines of coefficients in text window */
sprintf(codelinebuf, " % 6.3lf % 6.3lf % 6.3lf % 6.3lf %5.3lf %5.3lf\
%5.3lf %7.3lf% 5.3lf %5.3lf % 4.0lf % 4.0lf", pieceptr[i]->a, pieceptr[i]->b,
pieceptr[i]->c, pieceptr[i]->d, pieceptr[i]->e, pieceptr[i]->f,
pieceptr[i]->p, pieceptr[i]->dens, pieceptr[i]->s1, pieceptr[i]->s2,
pieceptr[i]->r1/0.017453293, pieceptr[i]->r2/0.017453293);
CodesText.FrontPen = (i == selpiece) ? 3 : 1; /* Selected piece in red */
CodesText.IText = (UBYTE*)codelinebuf;
CodesText.TopEdge = (N < MAX_N) ? 8L * i + 32L : 8L * i + 24L;
PrintIText(Textrp, &CodesText, 0L, 0L);
}
break;
} /* End switch */
PrintIText(Textrp, &RedText, 450L, 190L); /* 'Click Mouse...' text */
/*** Wait with text displayed, poll IDCMP until you get a SELECTDOWN */
while (!(message = (struct IntuiMessage *)GetMsg(TextWindow->UserPort)))
; /* here any event must be a SELECTDOWN due to IDCMP flag definition */
ReplyMsg(message);
while (!(message = (struct IntuiMessage *)GetMsg(TextWindow->UserPort)))
; /* get rid of SELECTUP message following the SELECTDOWN */
ReplyMsg(message);
CloseWindow(TextWindow); /* Close text display and return */
CloseScreen(TextScreen);
}
/*===========================================================================*/
PutDefOutline() /* Place default Outline in Outline Bitmap */
{
ModifyMousePtr(Window, 1); /* Bring up 'ZZ' pointer */
SetDrMd(r, JAM1);
SetAPen(r, 2L);
SetOPen(r, 2L);
SetWrMsk(r,0x0002); /* Write protect all planes except plane 1 */
SetRast(r, 0L);
DrawCircle(r, 138L, 93L, 22L); /* Face outline */
DrawCircle(r, 138L, 93L, 13L); /* To become mouth outline */
SetAPen(r, 0L);
SetOPen(r, 0L);
RectFill(r, 124L, 80L, 152L, 100L); /* Blot out top part of mouth circle */
SetAPen(r, 2L);
SetOPen(r, 2L);
DrawCircle(r, 129L, 85L, 3L); /* Left Eye */
DrawCircle(r, 147L, 85L, 3L); /* Right Eye */
exists_outline = 1;
SetWrMsk(r,0xFFFF);
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
}
/*===========================================================================*/
TransformPiece(source, dest, pc) /* Apply transformation of Piece */
/* To image in source bitplane, put result in dest piecemap. */
/* Return 1 if done OK, return 0 if a pixel overflowed plane boudary. */
/* Any overflow pixels are not put into the destination piecemap. */
/* Skips title bar and borders of source bitplane properly. */
/* Replaces doubles with scaled-up integers for speed. */
UBYTE *source; /* Pointer to 1st byte in a single Window-sized Bitplane */
UBYTE *dest; /* Pointer to first byte in target piecemap */
struct piece *pc; /* pointer to piece structure containing trans' coeffs */
{
#define LEFTBDRBITS 4 /* Width in BITS of left border of Window */
#define TOPBDRBYTES 440 /* bytes within Top Border of Window */
#define RIGHTBDRBYTES 5 /* bytes within right Border (must be integral) */
#define MAPROWBYTES 35 /* Number of bytes in a net row of piecemap */
#define MAPROWBYTESPLUS 40 /* Number of bytes in a gross row of piecemap */
#define PIECEMAPWIDTH GZZWIDTH+Window->BorderLeft
UBYTE *srcbyte; /* address of current byte in source bitplane */
int bitpos; /* bit position in byte (leftmost bit = 0) */
int rowbyte; /* number of current source byte within row */
int srcx, srcy, destx, desty; /* Source and destination pixel X-Y coords */
long ai, bi, ci, di, ei, fi; /* Scaled integer transformation coefficients */
long lbdri; /* Scaled LEFTBDRBITS */
int overflowflag = 0;
ModifyMousePtr(Window, 1); /* Bring up 'ZZ' pointer */
/* Erase piecemap */
BltClear((char*)dest, (long)RASSIZE(WIDTH,GZZHEIGHT), 1L);
/*** Convert coefficients to scaled integers */
ai = (long)(pc->a * 1000000);
bi = (long)(pc->b * 1000000);
ci = (long)(pc->c * 1000000);
di = (long)(pc->d * 1000000);
ei = (long)(pc->e * 1000000 * GZZWIDTH);
fi = (long)(pc->f * 1000000 * GZZWIDTH);
lbdri = (long)(LEFTBDRBITS * 1000000);
srcbyte = source + TOPBDRBYTES; /* Initialize srcbyte to after Top Border */
for (srcy = 0; srcy < GZZHEIGHT; srcy++) { /* Loop on source plane rows */
/* Loop on bytes in source row - up to right border only */
for (rowbyte = 0; rowbyte < MAPROWBYTES; rowbyte++) {
if (*srcbyte != 0) { /* If Source byte not empty */
for(bitpos = 0; bitpos < 8; bitpos++) { /* loop on bits in byte */
if ((*srcbyte & (128>>bitpos)) != 0) { /* current src pixel is '1' */
srcx = rowbyte * 8 + bitpos - LEFTBDRBITS;
/* do transformation */
destx = (ai * srcx + bi * srcy + ei + lbdri) / 1000000;
desty = (ci * srcx + di * srcy + fi) / 1000000;
if(destx < LEFTBDRBITS || destx >= PIECEMAPWIDTH ||
desty < 0 || desty >= GZZHEIGHT) /* Don't write transformed */
overflowflag = 1; /* pixel to dest - it is outside bitplane! */
else
/* write '1' pixel to destination. Expression to left of |= */
/* is destination byte address; 128>>bitpos is the bitmask. */
*( dest + desty*MAPROWBYTESPLUS + destx/8 ) |= 128>>(destx % 8);
} /* End if current source pixel is '1' */
} /* End loop on bits in byte */
} /* End If source byte not empty */
srcbyte++;
} /* End loop on bytes in source row */
srcbyte += RIGHTBDRBYTES; /* skip right border */
} /* End loop on source rows */
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
return(!overflowflag);
}
/*===========================================================================*/
SaveIFS() /* Save IFS coefficients, if any, to a disk file */
{
FILE *fopen(), *fp;
char *fnam, *p;
char *GetFileName();
int strcmp();
char *strcat();
long k;
if (drawmode != VECTOR) {
ShowError("No IFS to Save!");
return;
}
/*** Open disk file,deleting prev rev if any; if error, exit function */
fnam = GetFileName("Save to File:");
if (*fnam == '\0') {
return; /* do nothing - user selected CANCEL or no filename */
}
k = 0; /* Set k to 1 if filename ends with .ifs */
for (p = fnam; *p != '\0'; p++)
if (strcmp(p, ".ifs") == 0)
k = 1;
if (k == 0) /* Add .ifs to filename if needed */
strcat(fnam, ".ifs");
if ((fp = fopen(fnam, "w")) == NULL) {
ShowError(" Cannot open file!!!");
return;
}
/*** Save the current IFS codes to a disk file */
fprintf(fp, " A B C D E F P Dens S1\
S2 R1 R2\n");
for(i = 0; i <= N; i++)
fprintf(fp, " % 6.3lf % 6.3lf % 6.3lf % 6.3lf %5.3lf %5.3lf\
%5.3lf %7.3lf% 5.3lf %5.3lf % 4.0lf % 4.0lf\n", pieceptr[i]->a,
pieceptr[i]->b, pieceptr[i]->c, pieceptr[i]->d, pieceptr[i]->e,
pieceptr[i]->f, pieceptr[i]->p, pieceptr[i]->dens, pieceptr[i]->s1,
pieceptr[i]->s2, pieceptr[i]->r1/0.017453293,
pieceptr[i]->r2/0.017453293);
fclose(fp); /* close disk file */
}
/*===========================================================================*/
int LoadIFS(fnam) /* Load IFS Code variables from disk file */
char *fnam; /* Returns 1 if done OK, 0 if failed to load */
/* Skips lines of wrong form (e.g. text headers) */
/* and ignores excess info on a line (e.g. Geom. Coeffs) */
/* Calls Optimize() to create a Collage and assure */
{ /* Attractor will not overflow window */
FILE *fopen(), *fp;
int c, eofread, scan;
char linebuf[161]; /* Input lines will be truncated after 160 chars */
double mindens;
long xmin, xmax, ymin, ymax;
/* GZZ PIXEL coords of boundary rect of old (as-loaded) attractor*/
int j;
/*** Open disk file for reading */
if ((fp = fopen(fnam,"r")) == NULL) {
ShowError(" Cannot open file!!!");
return(0);
}
ClearIFS(); /* Erase old IFS (if any), set N to -1 */
/*** Load the IFS codes line by line */
eofread = 0;
while (N < MAX_N && !eofread) { /* Loop on lines in file */
if ((pieceptr[++N] = AllocPiece()) == NULL) { /* Allocate Piece */
N--; /* if couldn't allocate piece */
ShowError("Couldn't allocate memory!");
if (N == -1) { /* No memory for even one Piece - Quit program */
ShowError("Re-run with more free memory!");
CloseAll();
}
ShowError(" Aborting Load! ");
fclose(fp);
return(0);
}
/*** Read in a single line from file into memory, then sscanf it */
/* (Don't use fscanf from file because it ignores end of line */
for (i = 0; i < 160 && (c = getc(fp)) != EOF && c != '\n'; i++)
linebuf[i] = c;
linebuf[i] = '\0';
if (c != EOF && c != '\n') /* Line has been truncated after 160 chars */
while ((c = getc(fp)) != '\n' && c != EOF)
; /* Remove any other stuff on the file line */
if (c == EOF)
eofread = 1;
/* Now a null-terminated line is in linebuf & the file is positioned at */
/* start of next file line or past EOF;eofread is set if EOF was reached */
scan = sscanf(linebuf, "%lf %lf %lf %lf %lf %lf %lf", &pieceptr[N]->a,
&pieceptr[N]->b, &pieceptr[N]->c, &pieceptr[N]->d, &pieceptr[N]->e,
&pieceptr[N]->f, &pieceptr[N]->p);
if (scan == 7) { /* converted successfully 7 coeffs of one IFS */
/*** Check that coefficients a - d and p are in legal ranges */
if (pieceptr[N]->a < -1. || pieceptr[N]->a > 1. || pieceptr[N]->b < -1.||
pieceptr[N]->b > 1. || pieceptr[N]->c < -1. || pieceptr[N]->c > 1. ||
pieceptr[N]->d < -1. || pieceptr[N]->d > 1. ||
pieceptr[N]->p <= 0. || pieceptr[N]->p > 1.) {
ShowError("Coefficient out of Range!");
ShowError(" Aborting Load! ");
fclose(fp);
return(0);
}
/*** compute the geometrical coeffs from matrix coeffs read from file */
pieceptr[N]->s1 = sqrt(pieceptr[N]->a*pieceptr[N]->a +
pieceptr[N]->c*pieceptr[N]->c);
pieceptr[N]->s2 = sqrt(pieceptr[N]->b*pieceptr[N]->b +
pieceptr[N]->d*pieceptr[N]->d);
pieceptr[N]->r1 = myatan2(pieceptr[N]->c, pieceptr[N]->a);
pieceptr[N]->r2 = myatan2(-pieceptr[N]->b, pieceptr[N]->d);
pieceptr[N]->det = fabs(pieceptr[N]->a * pieceptr[N]->d -
pieceptr[N]->b * pieceptr[N]->c);
if (pieceptr[N]->det == 0.0)
pieceptr[N]->det = 0.01;
pieceptr[N]->dens = pieceptr[N]->p / pieceptr[N]->det;
/*** Compute new Box corners from new coeffs */
pieceptr[N]->boxo.x = pieceptr[N]->e * GZZWIDTH;
pieceptr[N]->boxo.y = pieceptr[N]->f * GZZWIDTH; /* sic! */
pieceptr[N]->boxx.x = (pieceptr[N]->a + pieceptr[N]->e) * GZZWIDTH;
pieceptr[N]->boxx.y = (pieceptr[N]->c + pieceptr[N]->f) * GZZWIDTH;
pieceptr[N]->boxy.x = (pieceptr[N]->b * GZZHEIGHT/GZZWIDTH +
pieceptr[N]->e) * GZZWIDTH;
pieceptr[N]->boxy.y = (pieceptr[N]->d * GZZHEIGHT/GZZWIDTH +
pieceptr[N]->f) * GZZWIDTH;
pieceptr[N]->boxz.x = pieceptr[N]->boxy.x + pieceptr[N]->boxx.x -
pieceptr[N]->boxo.x;
pieceptr[N]->boxz.y = pieceptr[N]->boxy.y + pieceptr[N]->boxx.y -
pieceptr[N]->boxo.y;
}
else /* scanf failed to match 7 doubles on line - skip it! */
FreePiece(pieceptr[N--]);
} /* End while loop on lines */
selpiece = N;
if (N == MAX_N && !eofread && getc(fp) != EOF) /* Exited loop at N==MAX_N */
ShowError("File too long; IFS may be truncated");
if (N == -1) { /* Not a single transformation was found! */
ShowError("No IFS found in File - Aborting Load!");
fclose(fp);
return(0);
}
/*** If probabilities read from file were cumulative, convert to non-cum */
if (pieceptr[N]->p == 1.000) {
for (i = N; i > 0; i--) {
pieceptr[i]->p = pieceptr[i]->p - pieceptr[i-1]->p;
pieceptr[i]->dens = pieceptr[i]->p / pieceptr[i]->det;
}
}
/*** Normalize Piece densities so smallest one is 1.000 */
mindens = 1000000.;
for (i = 0; i <= N; i++)
if (pieceptr[i]->dens < mindens)
mindens = pieceptr[i]->dens;
for (i = 0; i <= N; i++)
pieceptr[i]->dens /= mindens;
ComputeProbs(); /* Adjust all probabilities in case rounding errors in */
/* file made their sum != 1.000 */
fclose(fp); /* close disk file */
/* Transform loaded IFS to fit in window if it exceeds it, */
/* and generate Collage */
Optimize(0);
return(1);
}
/*===========================================================================*/
int Optimize(mode) /* Creates an Outline from current Attractor, creates */
int mode; /* a Collage from it and displays it. If mode==1, also */
/* modifies the IFS so its attractor fills the window. */
/* If mode==0, does this only if current Attractor would */
/* overflow the window. */
/* Returns 1 if successful and 0 if it failed (because */
{ /* not in Collage Editor) and no modifications were done.*/
long xmin, xmax, ymin, ymax; /* GZZ PIXEL coords of old boundary rect */
int px1, py1; /* GZZ PIXEL coords of Topleft corner of new boundary rect */
double x0,y0; /* REAL plane coords of Topleft corner of old boundary rect */
double x1,y1; /* REAL plane coords of Topleft corner of new boundary rect */
double m; /* Magnification to apply to attractor so it fills window */
double attrw, attrh; /* PIXEL Width & Height of old boundary rect */
struct piece tmppiece; /* will be used to hold temporary trans' coeffs */
int j;
if (drawmode != VECTOR) { /* Abort if not in Collage Editor! */
ShowError("No IFS!");
return(0);
}
ModifyMousePtr(Window, 1); /* Bring up 'ZZ' pointer */
SetRast(r, 0L); /* Erase Old Outline and Collage */
FindBoundary(&xmin, &xmax, &ymin, &ymax); /* Identify old boundary rect */
/*** If mode is 1, or mode is 0 but attractor exceeds window, modify IFS ***/
if (mode==1 || xmin<0 || xmax >= GZZWIDTH || ymin<0 || ymax >= GZZHEIGHT) {
/*** Compute required magnification and relocation of attractor */
attrw = (double)((xmax - xmin) + 1);
attrh = (double)((ymax - ymin) + 1);
if ((double)attrw/(double)attrh >= (double)GZZWIDTH/(double)GZZHEIGHT) {
m = 0.95 * (double)GZZWIDTH / attrw;
px1 = 0.025 * (double)GZZWIDTH;
py1 = 0.025 * (double)GZZHEIGHT +
(0.95 * (double)GZZHEIGHT - m * attrh) / 2.0;
}
else {
m = 0.95 * (double)GZZHEIGHT / attrh;
px1 = 0.025 * (double)GZZWIDTH +
(0.95 * (double)GZZWIDTH - m * attrw) / 2.0;
py1 = 0.025 * (double)GZZHEIGHT;
}
x0 = (double)xmin / (double)GZZWIDTH;
y0 = (double)ymin / (double)GZZWIDTH;
x1 = (double)px1 / (double)GZZWIDTH;
y1 = (double)py1 / (double)GZZWIDTH;
/*** Modify all piece coefficients to make new attractor fill window */
for (i = 0; i <= N; i++) { /* Loop on pieces */
pieceptr[i]->e = m * pieceptr[i]->e +
(pieceptr[i]->a - 1) * (m * x0 - x1) + pieceptr[i]->b * (m * y0 - y1);
pieceptr[i]->f = m * pieceptr[i]->f +
pieceptr[i]->c * (m * x0 - x1) + (pieceptr[i]->d - 1) * (m * y0 - y1);
/*** Recompute new Box corners from new coeffs */
pieceptr[i]->boxo.x = pieceptr[i]->e * GZZWIDTH;
pieceptr[i]->boxo.y = pieceptr[i]->f * GZZWIDTH; /* sic! */
pieceptr[i]->boxx.x = (pieceptr[i]->a + pieceptr[i]->e) * GZZWIDTH;
pieceptr[i]->boxx.y = (pieceptr[i]->c + pieceptr[i]->f) * GZZWIDTH;
pieceptr[i]->boxy.x = (pieceptr[i]->b * GZZHEIGHT/GZZWIDTH +
pieceptr[i]->e) * GZZWIDTH;
pieceptr[i]->boxy.y = (pieceptr[i]->d * GZZHEIGHT/GZZWIDTH +
pieceptr[i]->f) * GZZWIDTH;
pieceptr[i]->boxz.x = pieceptr[i]->boxy.x + pieceptr[i]->boxx.x -
pieceptr[i]->boxo.x;
pieceptr[i]->boxz.y = pieceptr[i]->boxy.y + pieceptr[i]->boxx.y -
pieceptr[i]->boxo.y;
} /* End loop on pieces */
} /* End if mode==1... */
RenderImage(1); /* Render new attractor in OUTLINE Bitplane */
CopyMem((char*)Window->RPort->BitMap->Planes[1],
(char*)outlinebufptr, (long)RASSIZE(WIDTH,HEIGHT));
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
/*** Transform the new Outline (=attractor) into all pieces' piecemaps */
/*** Draw each piece into the collage as you go */
selpiece = N;
for (i = 0; i <= N-1; i++) { /* Loop on deselected pieces */
TransformPiece(outlinebufptr, pieceptr[i]->piecemap, pieceptr[i]);
/* Blit this piece from its piecemap to plane 0 */
SetWrMsk(r,0x0001); /* Write protect all planes except plane 0 */
SetAPen(r, 1L);
BltTemplate((char*)pieceptr[i]->piecemap,(long)Window->BorderLeft,
(long)WIDTH/8, r, 0L, 0L, (long)GZZWIDTH, (long)GZZHEIGHT);
}
/* Now transform Selected Piece & Blit it from piecemap to plane 2 */
TransformPiece(outlinebufptr, pieceptr[i]->piecemap, pieceptr[i]);
SetWrMsk(r,0x0004); /* Write protect all planes except plane 2 */
SetAPen(r, 4L);
BltTemplate((char*)pieceptr[selpiece]->piecemap,(long)Window->BorderLeft,
(long)WIDTH/8, r, 0L, 0L, (long)GZZWIDTH, (long)GZZHEIGHT);
DrawBox(); /* Draw Vector Box of Selected Piece */
/* Note that Rastport's WrMask is restored within DrawBox() */
return(1);
}
/*===========================================================================*/
RenderImage(z) /* If z == 0, Render the Attractor in Image Screen at current */
int z; /* resolution & depth settings; stop and return on click in Image */
/* screen. If z == 1, render it in Outline bitplane. */
/* Probabilities and coefficients are scaled to integers so can use */
/* faster integer math */
{
struct Message * GetMsg();
struct IntuiMessage *message;
int randprob; /* Random probability value */
double sum; /* cum probability */
int k;
long unitwidth, unitheight;
/* width, height in image screen pixels of unit square in the plane */
long iter; /* Iteration counter */
struct RastPort *imagerp; /* Pointer to rastport of Image window */
long pix; /* Color (Pen #) of a pixel */
long ReadPixel();
long ai[MAX_N+1], bi[MAX_N+1], ci[MAX_N+1],
di[MAX_N+1], ei[MAX_N+1], fi[MAX_N+1]; /* Scaled integer coefficients */
long xi, yi, tmpxi; /* Scaled integer pixel coordinates */
int cumprobi[MAX_N+2]; /* Scaled integer Cum Probabilities */
/* cumprobi array has MAX_N+2 elements because using MAX_N+1 caused a */
/* Crash for unclear reasons ?!?! */
/*** Prepare stuff for iteration loop ***/
if (z == 0) { /* Rendering is in Image Screen */
/*** Open Image Window in its screen (Closing any previous image screen) */
if (exists_image)
CloseImageScreen();
OpenImageScreen(renderwidth, renderheight, renderdepth);
/* OpenImageScreen() also opens ImageWindow */
imagerp = ImageWindow->RPort;
SetAPen(imagerp,2L); /* Will be modified in loop for Greyscale rendering */
SetDrMd(imagerp, JAM1);
SetWindowTitles(ImageWindow, -1L,
(char *)" Click in screen to stop rendering");
unitwidth = GZZWIDTH*(renderwidth/320); /* GZZWIDTH is of Collage window!*/
unitheight = GZZWIDTH * (renderheight/200);
}
else { /* Rendering in Outline plane */
SetWrMsk(r, 0x0002); /* Write protect all planes except plane 1 */
SetAPen(r, 2L);
SetDrMd(r, JAM1);
unitwidth = unitheight = GZZWIDTH;
}
srand((unsigned int)(time(NULL)%10000L)); /* seed random gen from sys time*/
sum = 0;
for (k = 0; k <= N; k++) { /* Scale Coefficients as longs */
ai[k] = (long)(pieceptr[k]->a * 1000000);
bi[k] = (long)(pieceptr[k]->b * 1000000);
ci[k] = (long)(pieceptr[k]->c * 1000000);
di[k] = (long)(pieceptr[k]->d * 1000000);
ei[k] = (long)(pieceptr[k]->e * 1000000 * unitwidth);
fi[k] = (long)(pieceptr[k]->f * 1000000 * unitwidth);
sum = sum + pieceptr[k]->p; /* Compute scaled Cum Probabilities */
cumprobi[k] = (int)(sum * (double)RAND_MAX);
}
xi = unitwidth / 3; /* Initial coordinates */
yi = unitwidth / 3;
/*** Iterate until user clicks in Image window or until 1000 points ***/
/*** (depending on z) ***/
for (iter = 0; 1; iter++) { /* endless loop */
/*** Select a Piece at random */
randprob = rand();
/* rand() returns a random # (between 0 - RAND_MAX) */
for (k = 0; cumprobi[k] < randprob; k++) {
/* the following IF is to trap problem case when randprob = RAND_MAX */
/* exactly and cum probability is RAND_MAX minus slight delta due to */
/* rounding errors */
if (k > N) {
k--;
break;
}
}
/* Apply transformation #k to previous (x,y) */
tmpxi = (ai[k] * xi + bi[k] * yi + ei[k]) / 1000000;
yi = (ci[k] * xi + di[k] * yi + fi[k]) / 1000000;
xi = tmpxi;
if (iter > 19) { /* Render the pixel (except 1st 20 points) */
if (z == 0) { /*** draw in Image Screen, quit on mouseclick in it */
if (renderdepth > 1) { /* Grayscale rendering */
pix = ReadPixel(imagerp, xi, yi * unitheight / unitwidth);
if (++pix < (1<<renderdepth)) {
SetAPen(imagerp, pix);
WritePixel(imagerp, xi, yi * unitheight / unitwidth);
}
}
else /* B&W rendering - A Pen was set outside main loop */
WritePixel(imagerp, xi, yi * unitheight / unitwidth);
/*** Quit rendering loop if user clicked in ImageWindow */
if (message = (struct IntuiMessage *)GetMsg(ImageWindow->UserPort)) {
ReplyMsg(message);
if (message->Code == SELECTUP) {
SetWindowTitles(ImageWindow,
(char *)" Click in screen to push it back", -1L);
ShowTitle(ImageScreen, FALSE); /* Hide screen depth gadgets! */
break; /* From for iter */
}
}
}
else { /* z == 1, draw in outline plane, quit after 1000 iters */
WritePixel(r, xi, yi);
if (iter > 999)
break; /* From for iter */
}
} /* End if iter > 19 */
} /* End for iter */
if (z == 0) { /*** Wait for user click in Image screen to push it to back */
while (!(message = (struct IntuiMessage*)GetMsg(ImageWindow->UserPort)))
; /* Wait for a message */
ReplyMsg(message);
SetWindowTitles(ImageWindow,
(char *)" ", (char *)" Click in screen to push it back");
ShowTitle(ImageScreen, TRUE); /* OK to have depth gadgets now */
ScreenToBack(ImageScreen);
MoveScreen(ImageScreen, 0L, (long)(-1*ImageScreen->TopEdge));
ScreenToFront(Screen);
ActivateWindow(Window);
}
else /* z == 1, unprotect Outline window planes */
SetWrMsk(r, 0xFFFF);
}
/*===========================================================================*/
SaveILBM() /* Saves the current Image to an IFF disk file */
{
LONG file; /* File handle [we use AmigaDOS Open(), not Manx open()] */
UBYTE *savebuffer;
char *fnam;
if (exists_image == 0) {
ShowError("No Image to save!");
return;
}
fnam = GetFileName("Save to File:"); /* Get the filename */
if (*fnam == '\0') /* User selected CANCEL or gave no filename */
return;
if ((file = Open(fnam, MODE_NEWFILE)) == NULL) {
ShowError("Can't open file!");
return;
}
if ((savebuffer = (UBYTE *)AllocMem(8000L, MEMF_CHIP|MEMF_PUBLIC)) == NULL) {
ShowError("Can't allocate Save Buffer Memory!");
return;
}
/* Use EA IFF routine PutPict() to save the image to file */
ModifyMousePtr(Window, 1); /* Bring up 'ZZ' pointer */
SetWindowTitles(ImageWindow,-1L,
(char *)"");
ShowTitle(ImageScreen, FALSE); /* Hide screen depth gadgets! */
ActivateWindow(ImageWindow); /* To make title change take effect */
ActivateWindow(Window);
PutPict(file, ImageWindow->RPort->BitMap, ImageScreen->Width, ImageScreen->Height,
(WORD *)(&(ImageScreen->ViewPort))->ColorMap->ColorTable, savebuffer,8000L);
SetWindowTitles(ImageWindow,-1L,
(char *)" Click in screen to push it back");
ShowTitle(ImageScreen, TRUE); /* OK to have depth gadgets now */
ActivateWindow(ImageWindow); /* To make title change take effect */
ActivateWindow(Window);
FreeMem(savebuffer, 8000L);
Close(file);
ModifyMousePtr(Window, -1); /* Remove 'ZZ' pointer */
}
/*===========================================================================*/
struct piece *AllocPiece() /* Allocate memory for a piece structure and */
{ /* its piecemap. Return pointer to the piece structure */
/* Or NULL if can't allocate memory */
struct piece *tmppieceptr;
UBYTE *mapptr;
/* Allocate memory for piece structure */
if ((tmppieceptr =
(struct piece *)AllocMem((long)sizeof(struct piece), NULL)) == NULL) {
ShowError("Can't allocate Memory!");
return(NULL);
}
/* Allocate piecemap CHIP RAM */
if ((mapptr = (UBYTE*)AllocRaster((long)WIDTH, (long)GZZHEIGHT)) == NULL) {
FreeMem((void*)tmppieceptr, (long)sizeof(struct piece));
ShowError("Can't allocate Memory!");
return(NULL);
}
/* Clear piecemap */
BltClear((char*)mapptr, (long)RASSIZE(WIDTH,GZZHEIGHT), 1L);
tmppieceptr->piecemap = mapptr; /* Link bitplane to piece structure */
return(tmppieceptr);
}
/*===========================================================================*/
FreePiece(piecepntr) /* Frees the memory used for a piece structure */
struct piece *piecepntr; /* and its piecemap. */
{
/* Deallocate CHIP RAM of piecemap bitplane */
FreeRaster((void*)(piecepntr->piecemap), (long)WIDTH, (long)GZZHEIGHT);
/* Deallocate memory of piece structure */
FreeMem((void*)piecepntr, (long)sizeof(struct piece));
}
/*===========================================================================*/
p(text) /* screen text output routine, similar to BASIC's PRINT */
/* puts text in consecutive lines in rastport pointed at by the */
/* external pointer Textrp. Line position is maintained between */
/* calls, but is reset to top if text==NULL. No overflow check */
char *text; /* is done -- text should fit in rastport area! */
{
static struct IntuiText Textline = {
1, 0, JAM1, /* FrontPen, BackPen, DrawMode */
0, NULL, /* LeftEdge, TopEdge */
NULL, /* ITextFont */
NULL, NULL /* IText, NextText */
};
static int line = 0; /* vert. position of line to be printed next (0 - 24) */
if (text == NULL) /* reset to top line of rastport */
line = 0;
else {
Textline.TopEdge = 8 * line; /* Put text into line on screen */
Textline.IText = (UBYTE*)text;
PrintIText(Textrp, &Textline, 0L, 0L);
line++; /* increment line for next call */
}
}
/*===========================================================================*/
FindBoundary(xminp, xmaxp, yminp, ymaxp) /* Iterates IFS without drawing */
/* and returns PIXEL coords of boundary rectangle of attractor */
/* in variables pointed at by its arguments */
/* Uses float math, not scaled int, to avoid overflow on very */
/* large coeffs of loaded IFS files from other programs */
long *xminp, *xmaxp, *yminp, *ymaxp; /* Pointers! */
{
int randprob; /* Random probability value */
double sum; /* cum probability */
int k;
long iter; /* Iteration counter */
double xd, yd, tmpxd; /* Real pixel coordinates */
double xdmin, ydmin, xdmax, ydmax; /* Real boundary rect coords */
int cumprobi[MAX_N+2]; /* Scaled integer Cum Probabilities */
/* cumprobi array has MAX_N+2 elements because using MAX_N+1 caused a */
/* Crash for unclear reasons in RenderImage() ?!?! */
/*** Prepare stuff for iteration loop ***/
srand((unsigned int)(time(NULL)%10000L)); /* seed random gen from sys time*/
sum = 0;
for (k = 0; k <= N; k++) { /* Scale Coefficients as longs */
sum = sum + pieceptr[k]->p; /* Compute scaled Cum Probabilities */
cumprobi[k] = (int)(sum * (double)RAND_MAX);
}
xdmin = 1000000000.; /* Initialize boundary rectangle coords */
xdmax = -1000000000.;
ydmin = 1000000000.;
ydmax = -1000000000.;
xd = 0.3; /* Initial coordinates */
yd = 0.3;
/*** Iterate 1000 times without drawing ***/
for (iter = 0; iter < 1000; iter++) {
/*** Select a Piece at random */
randprob = rand();
/* rand() returns a random # (between 0 - RAND_MAX) */
for (k = 0; cumprobi[k] < randprob; k++) {
/* the following IF is to trap problem case when randprob = RAND_MAX */
/* exactly and cum probability is RAND_MAX minus slight delta due to */
/* rounding errors */
if (k > N) {
k--;
break;
}
}
/* Apply transformation #k to previous (x,y) */
tmpxd = pieceptr[k]->a * xd + pieceptr[k]->b * yd + pieceptr[k]->e;
yd = pieceptr[k]->c * xd + pieceptr[k]->d * yd + pieceptr[k]->f;
xd = tmpxd;
if (iter > 19) { /* Adjust rectangle (except 1st 20 points) */
if (xd < xdmin)
xdmin = xd;
if (xd > xdmax)
xdmax = xd;
if (yd < ydmin)
ydmin = yd;
if (yd > ydmax)
ydmax = yd;
}
} /* End for iter */
/*** Convert real coords to pixel coords for returned values */
*xminp = (long)(xdmin * GZZWIDTH);
*xmaxp = (long)(xdmax * GZZWIDTH);
*yminp = (long)(ydmin * GZZWIDTH);
*ymaxp = (long)(ydmax * GZZWIDTH);
}
/*===========================================================================*/